{"openapi":"3.0.0","info":{"version":"1.0.0","title":"Product Management Service API","description":"API documentation for Product Management Service","contact":{"name":"Galtea AI"}},"externalDocs":{"description":"Galtea Platform Documentation","url":"https://docs.galtea.ai"},"servers":[{"url":"https://api.galtea.ai"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key authorization. Pass your API key in the Authorization header as a Bearer token. Both new (`gsk_*`) and legacy (`gsk-`) API keys are accepted, e.g. `Authorization: Bearer gsk_...` or `Authorization: Bearer gsk-...`."}},"schemas":{"Product":{"type":"object","properties":{"id":{"type":"string","example":"prod_123"},"organizationId":{"type":"string","example":"org_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"Sample Product"},"description":{"type":"string","example":"Sample product description"},"riskLevel":{"type":"string","enum":["PROHIBITED","GPAI","GPAI_SYSTEMIC","HIGH","SPECIAL_SYSTEM"],"nullable":true,"description":"EU AI Act risk classification. PROHIBITED: banned AI use cases. GPAI: general-purpose AI. GPAI_SYSTEMIC: GPAI with systemic risk. HIGH: high-risk AI system. SPECIAL_SYSTEM: special-category system.","example":"HIGH"},"operatorType":{"type":"string","enum":["AUTHORISED_REPRESENTATIVE","DEPLOYER","DISTRIBUTER","IMPORTER","PRODUCT_MANUFACTURER","PROVIDER"],"nullable":true,"description":"EU AI Act operator role classification.","example":"PROVIDER"},"securityBoundaries":{"type":"string","nullable":true,"example":"Internal use only"},"capabilities":{"type":"string","nullable":true,"example":"Can process and analyze data"},"inabilities":{"type":"string","nullable":true,"example":"Cannot process sensitive financial data"},"policies":{"type":"string","nullable":true,"example":"Must comply with data protection regulations"},"otelOutputSourceRule":{"type":"object","nullable":true,"description":"Recover a turn's user-visible output for templated or non-LLM replies whose final answer lives on a non-LLM span. Set per product or version (version wins). Applied only when no LLM output is present.","properties":{"spanName":{"type":"string","description":"Exact OTLP span name to match.","example":"ExecuteActivity:save_reply"},"attribute":{"type":"string","description":"Span attribute key holding the JSON blob (string or object) to read.","example":"app.arguments"},"path":{"type":"string","description":"JSONPath into the parsed attribute value, resolving to the output text.","example":"$[0].message.content"},"predicate":{"type":"object","nullable":true,"description":"Optional gate: apply the rule only when the node at predicate.path equals predicate.equals.","properties":{"path":{"type":"string","example":"$[0].message.role"},"equals":{"type":"string","example":"assistant"}},"required":["path","equals"]}},"required":["spanName","attribute","path"],"example":{"spanName":"ExecuteActivity:save_reply","attribute":"app.arguments","path":"$[0].message.content","predicate":{"path":"$[0].message.role","equals":"assistant"}}},"autoCloseScope":{"type":"string","enum":["NONE","DEVELOPMENT","PRODUCTION","ALL"],"default":"PRODUCTION","description":"Which sessions the product-level auto-close sweep considers. PRODUCTION (default) closes only production sessions; DEVELOPMENT only test sessions; ALL both; NONE disables auto-close.","example":"PRODUCTION"},"autoCloseInactivityMinutes":{"type":"integer","minimum":1,"default":30,"description":"Minutes of inactivity after which an eligible session is auto-closed.","example":30},"closedSessionInferenceCreationPolicy":{"type":"string","enum":["REJECT","IGNORE"],"default":"IGNORE","description":"What happens when a new inference result is created for an already-closed session. IGNORE (default) drops it silently; REJECT returns an error.","example":"IGNORE"},"tags":{"type":"array","items":{"type":"string"},"example":["internal","beta"],"description":"Free-form labels for organizing products. Normalized to lowercase and trimmed on save."},"source":{"type":"string","nullable":true,"readOnly":true,"description":"Demo key the product was cloned from (e.g. \"banking\"); null for user-created products. Server-stamped on demo-clone; not client-writable.","example":"banking"},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"Test":{"type":"object","properties":{"id":{"type":"string","example":"test_123"},"productId":{"type":"string","nullable":true,"example":"prod_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"Quality Test"},"type":{"type":"string","enum":["QUALITY","RED_TEAMING","SCENARIOS"],"example":"QUALITY"},"groundTruthUri":{"type":"string","nullable":true,"example":"s3://my-bucket/tests/test_123/ground-truth.csv","description":"Canonical storage URI of the ground-truth file, derived from the presigned URL supplied at creation. S3: `s3://<bucket>/<key>`. Azure Blob: blob URL with the SAS query stripped (e.g. `https://<account>.blob.core.windows.net/<container>/<path>`)."},"uri":{"type":"string","nullable":true,"example":"s3://my-bucket/tests/test_123/test.csv","description":"Canonical storage URI of the uploaded custom test file. Same format rules as `groundTruthUri`."},"error":{"type":"string","nullable":true},"status":{"type":"string","enum":["PENDING","SUCCESS","FAILED","AUGMENTING","EXTENDING","CANCELLED"],"example":"SUCCESS"},"fewShot":{"type":"string","nullable":true,"example":"Example few-shot learning data","description":"Optional few-shot examples (input/output pairs) used to guide test-case generation for QUALITY tests."},"languageCode":{"type":"string","nullable":true,"example":"es-MX","description":"BCP-47 language tag (e.g. en, es-MX). The region subtag selects the regional variety in simulated user messages and voice synthesis; generated test text keeps the base language. The value is stored as the full tag."},"backgroundNoiseProfile":{"type":"string","nullable":true,"enum":["office","street","car","white","pink"],"example":"street","description":"Background noise mixed into the simulated caller audio during a voice test. Clip-backed (office, street, car) or synthetic (white, pink). Null means off; set together with backgroundNoiseLevel."},"backgroundNoiseLevel":{"type":"string","nullable":true,"enum":["light","medium","heavy"],"example":"medium","description":"How loud the background noise is relative to the caller speech. Null means off; set together with backgroundNoiseProfile."},"variants":{"type":"array","items":{"type":"string"},"example":["rag","summarization"],"description":"Test variants. QUALITY: rag, entity_extraction, summarization, classification, translation, correction, other. RED_TEAMING: data_leakage, financial_attacks, illegal_activities, misuse, toxicity, custom."},"customVariantDescription":{"type":"string","nullable":true,"example":"Custom variant description"},"strategies":{"type":"array","items":{"type":"string"},"example":["original"],"description":"Generation strategies. \"original\" is the default for RED_TEAMING. At least one strategy is required for SCENARIOS tests."},"customUserPersona":{"type":"string","nullable":true,"example":"Business analyst"},"maxTestCases":{"type":"integer","nullable":true,"example":100},"models":{"type":"array","items":{"type":"string"},"example":["gpt-4","claude-3"]},"sourceTestId":{"type":"string","nullable":true},"dataCatalogUri":{"type":"string","nullable":true,"example":"s3://my-bucket/tests/test_123/data-catalog.json","description":"Canonical storage URI of the data-catalog file (SCENARIOS tests only). Same format rules as `groundTruthUri`."},"metadata":{"type":"object","nullable":true,"example":{"key":"value"}},"specificationId":{"type":"string","nullable":true,"example":"spec_123"},"isExtendable":{"type":"boolean","description":"True when the test can be extended by re-running its original generator (generated tests; QUALITY only when it has a ground-truth document). False for uploaded tests.","example":true},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"TestInput":{"type":"object","required":["productId","name","type"],"properties":{"productId":{"type":"string","description":"Product ID","example":"prod_123"},"name":{"type":"string","description":"Test name","example":"Quality Test"},"type":{"type":"string","enum":["QUALITY","RED_TEAMING","SCENARIOS"],"example":"QUALITY"},"specificationId":{"type":"string","description":"Specification ID (can auto-derive type/variants)","example":"spec_123"},"groundTruthUri":{"type":"string","description":"Presigned GET URL (S3 `X-Amz-*` query or Azure Blob SAS) for a ground-truth file previously uploaded via the storage PUT-presign endpoint. The server strips the signing query and persists the underlying storage URI. Cannot be combined with `sourceTestId`.","example":"https://my-bucket.s3.amazonaws.com/tests/ground-truth.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=..."},"uri":{"type":"string","description":"Presigned GET URL for a fully prepared custom test file previously uploaded via the storage PUT-presign endpoint. When provided, no test-case generation runs: the file is ingested as-is, the test is created in `SUCCESS` state, and `maxTestCases`, generator-related fields, and credit checks are skipped. Cannot be combined with `sourceTestId` or `dataCatalogUri`. Must be non-empty.","example":"https://my-bucket.s3.amazonaws.com/tests/test.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=..."},"fewShot":{"type":"string","description":"Optional few-shot examples used to guide test-case generation for QUALITY tests.","example":"Q: What is 2+2? A: 4"},"languageCode":{"type":"string","example":"es-MX","description":"BCP-47 language tag (e.g. en, es-MX). The region subtag selects the regional variety in simulated user messages and voice synthesis; generated test text keeps the base language. The value is stored as the full tag."},"backgroundNoiseProfile":{"type":"string","nullable":true,"enum":["office","street","car","white","pink"],"example":"street","description":"Background noise mixed into the simulated caller audio during a voice test. Clip-backed (office, street, car) or synthetic (white, pink). Null means off; set together with backgroundNoiseLevel."},"backgroundNoiseLevel":{"type":"string","nullable":true,"enum":["light","medium","heavy"],"example":"medium","description":"How loud the background noise is relative to the caller speech. Null means off; set together with backgroundNoiseProfile."},"variants":{"type":"array","items":{"type":"string"},"example":["rag"],"description":"Test variants. QUALITY: rag, entity_extraction, summarization, classification, translation, correction, other. RED_TEAMING: data_leakage, financial_attacks, illegal_activities, misuse, toxicity, custom."},"customVariantDescription":{"type":"string","description":"Custom variant description","example":"Custom test variant"},"strategies":{"type":"array","items":{"type":"string"},"example":["original"],"description":"Generation strategies. \"original\" is the default for RED_TEAMING. At least one strategy is required for SCENARIOS tests."},"customUserPersona":{"type":"string","example":"Business analyst"},"maxTestCases":{"type":"integer","example":100},"maxIterations":{"type":"integer","minimum":1,"description":"SCENARIOS only. Maximum number of conversation turns per generated scenario when scenario generation is executed. If omitted, the scenario-generator default is used. If `uri` is provided, no scenario generation runs, so this field is ignored at test-creation time. When generation runs, the value is forwarded to the scenario-generator and persisted on each generated test case. Ignored for QUALITY and RED_TEAMING tests.","example":10},"models":{"type":"array","items":{"type":"string"},"example":["gpt-4"]},"sourceTestId":{"type":"string","description":"Source QUALITY test ID whose approved test cases seed a SCENARIOS test. Only valid when `type = SCENARIOS`. Cannot be combined with `uri` or `groundTruthUri`.","example":"test_123"},"dataCatalogUri":{"type":"string","description":"Presigned GET URL for a data-catalog file previously uploaded via the storage PUT-presign endpoint. Only valid when `type = SCENARIOS`. Cannot be combined with `uri`.","example":"https://my-bucket.s3.amazonaws.com/tests/data-catalog.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Signature=..."},"metadata":{"type":"object","nullable":true,"description":"Arbitrary key-value metadata","example":{"key":"value"}}}},"TestUpdateInput":{"type":"object","additionalProperties":false,"description":"Test update payload. Only `name` and `metadata` are mutable post-creation — any other field (type, variants, URIs, strategies, etc.) will be rejected with a 400.","properties":{"name":{"type":"string","description":"New test name. Must be a non-empty string; leading/trailing whitespace is trimmed.","example":"Quality Test (renamed)"},"metadata":{"type":"object","nullable":true,"description":"Arbitrary key-value metadata. Replaces the existing metadata object wholesale.","example":{"key":"value"}}}},"Version":{"type":"object","properties":{"id":{"type":"string","example":"ver_123"},"productId":{"type":"string","example":"prod_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"1.0.0"},"description":{"type":"string","nullable":true,"example":"Version description"},"modelId":{"type":"string","nullable":true,"example":"model_123"},"systemPrompt":{"type":"string","nullable":true,"example":"You are a helpful assistant"},"datasetUri":{"type":"string","nullable":true,"example":"https://example.com/dataset.csv"},"datasetDescription":{"type":"string","nullable":true,"example":"Training dataset"},"guardrails":{"type":"string","nullable":true,"example":"Safety guidelines"},"otelOutputSourceRule":{"type":"object","nullable":true,"description":"Recover a turn's user-visible output for templated or non-LLM replies whose final answer lives on a non-LLM span. Set per product or version (version wins). Applied only when no LLM output is present.","properties":{"spanName":{"type":"string","description":"Exact OTLP span name to match.","example":"ExecuteActivity:save_reply"},"attribute":{"type":"string","description":"Span attribute key holding the JSON blob (string or object) to read.","example":"app.arguments"},"path":{"type":"string","description":"JSONPath into the parsed attribute value, resolving to the output text.","example":"$[0].message.content"},"predicate":{"type":"object","nullable":true,"description":"Optional gate: apply the rule only when the node at predicate.path equals predicate.equals.","properties":{"path":{"type":"string","example":"$[0].message.role"},"equals":{"type":"string","example":"assistant"}},"required":["path","equals"]}},"required":["spanName","attribute","path"],"example":{"spanName":"ExecuteActivity:save_reply","attribute":"app.arguments","path":"$[0].message.content","predicate":{"path":"$[0].message.role","equals":"assistant"}}},"initializationEndpointConnectionId":{"type":"string","nullable":true,"example":"ec_123"},"conversationEndpointConnectionId":{"type":"string","nullable":true,"example":"ec_123"},"finalizationEndpointConnectionId":{"type":"string","nullable":true,"example":"ec_123"},"phoneConnectionId":{"type":"string","nullable":true,"description":"The version's phone connection (telephony conversation target). At most one conversation target may be set across conversationEndpointConnectionId, phoneConnectionId, and webRtcConnectionId.","example":"phoneConnection_123"},"webRtcConnectionId":{"type":"string","nullable":true,"description":"The version's WebRTC connection (live two-way audio conversation target). At most one conversation target may be set across conversationEndpointConnectionId, phoneConnectionId, and webRtcConnectionId.","example":"webRtcConnection_123"},"parentVersionId":{"type":"string","nullable":true,"example":"ver_122","description":"Id of the version this one was revised from (its direct parent in the revision lineage). On create, providing this value records the parent edge; the parent must belong to the same product. Omit or null to create a root version with no parent. On responses, this is the recorded parent edge (null for roots)."},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"TestCase":{"type":"object","properties":{"id":{"type":"string","example":"tc_123"},"testId":{"type":"string","example":"test_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"input":{"type":"object","nullable":true,"description":"Structured input data. For plain text input, format is { user_message: \"...\" }","example":{"user_message":"What is the capital of France?"}},"expectedOutput":{"type":"string","nullable":true,"example":"Paris"},"expectedTools":{"type":"array","items":{"type":"string"},"example":["search","calculator"]},"context":{"type":"object","nullable":true,"description":"Structured context data. For plain text context, format is { value: \"...\" }","example":{"value":"Geography question"}},"source":{"type":"string","nullable":true,"example":"manual"},"sourceFile":{"type":"string","nullable":true},"confidence":{"type":"number","nullable":true,"example":0.95},"confidenceReason":{"type":"string","nullable":true,"example":"High quality data"},"variant":{"type":"string","nullable":true,"example":"VARIANT_1"},"strategy":{"type":"string","nullable":true,"example":"STRATEGY_1"},"languageCode":{"type":"string","nullable":true,"example":"es-MX","description":"BCP-47 language tag (e.g. en, es-MX). The region subtag selects the regional variety in simulated user messages and voice synthesis; generated test text keeps the base language. The value is stored as the full tag."},"gender":{"type":"string","nullable":true,"enum":["MALE","FEMALE"],"example":"FEMALE","description":"Persona-derived gender (\"MALE\"/\"FEMALE\") for the male/female synthesized caller voice in phone (voice) evaluations. Stored only for now (not consumed yet). Ignored by text evaluations."},"backgroundNoiseProfile":{"type":"string","nullable":true,"enum":["office","street","car","white","pink"],"example":"street","description":"Background noise mixed into the simulated caller audio during a voice test. Clip-backed (office, street, car) or synthetic (white, pink). Null means off; set together with backgroundNoiseLevel."},"backgroundNoiseLevel":{"type":"string","nullable":true,"enum":["light","medium","heavy"],"example":"medium","description":"How loud the background noise is relative to the caller speech. Null means off; set together with backgroundNoiseProfile."},"userPersona":{"type":"string","nullable":true,"example":"Student"},"scenario":{"type":"string","nullable":true,"example":"Educational quiz"},"goal":{"type":"string","nullable":true,"example":"Test geographical knowledge"},"archetype":{"type":"string","nullable":true,"example":"data_grounded"},"specRelevance":{"type":"string","nullable":true,"example":"direct"},"stoppingCriterias":{"type":"array","items":{"type":"string"},"example":["MAX_ITERATIONS","GOAL_ACHIEVED"]},"maxIterations":{"type":"integer","nullable":true,"example":10},"isAugmented":{"type":"boolean","example":false},"reviewedById":{"type":"string","nullable":true,"example":"user_456"},"userScore":{"type":"integer","nullable":true,"example":5},"userScoreReason":{"type":"string","nullable":true,"example":"Accurate and complete"},"creditsUsed":{"type":"integer","nullable":true,"example":1},"sourceTestCaseId":{"type":"string","nullable":true},"testCaseGroupId":{"type":"string","nullable":true,"description":"Revision family key shared by every revision of this test case.","example":"testCaseGroup_123"},"parentTestCaseId":{"type":"string","nullable":true,"description":"The revision this row was forked from; null for a family root."},"legacyAt":{"type":"string","format":"date-time","nullable":true,"description":"Set when this revision was superseded by a newer one; null for the active head."},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"Evaluation":{"type":"object","properties":{"id":{"type":"string","example":"eval_123"},"metricId":{"type":"string","example":"metric_123"},"sessionId":{"type":"string","example":"session_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"status":{"type":"string","enum":["PENDING","PENDING_HUMAN","SUCCESS","FAILED","SKIPPED","CANCELLED"],"example":"SUCCESS"},"inferenceResultId":{"type":"string","nullable":true,"example":"ir_123"},"score":{"type":"number","nullable":true,"example":0.95},"reason":{"type":"string","nullable":true,"example":"High quality response"},"error":{"type":"string","nullable":true},"canRetry":{"type":"boolean","nullable":true,"example":false},"creditsUsed":{"type":"integer","nullable":true,"example":1},"conversationSimulatorVersion":{"type":"string","nullable":true,"example":"1.0.0"},"humanEvaluatorId":{"type":"string","nullable":true,"description":"User ID of the human evaluator"},"humanEvaluatorStartedAt":{"type":"string","nullable":true,"format":"date-time"},"humanScore":{"type":"number","nullable":true,"description":"Human-provided annotation score"},"humanReason":{"type":"string","nullable":true,"description":"Human-provided annotation reason"},"humanEvaluatorFinishedAt":{"type":"string","nullable":true,"format":"date-time","description":"Timestamp when human evaluation was submitted"},"failedTurns":{"type":"array","items":{"type":"string"},"description":"Conversation turns that failed"},"monitorId":{"type":"string","nullable":true,"description":"ID of the monitor that dispatched this evaluation"},"monitorSettledAtTurn":{"type":"integer","nullable":true,"description":"Session turn count when the monitor scored it"},"monitorSamplingPercentage":{"type":"number","nullable":true,"description":"Sampling percentage in effect when the monitor scored this session"},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","nullable":true,"format":"date-time"},"evaluatedAt":{"type":"string","nullable":true,"format":"date-time"},"metricLegacyAt":{"type":"string","nullable":true,"format":"date-time"},"metricDisabledAt":{"type":"string","nullable":true,"format":"date-time"},"testCaseLegacyAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","metricId","sessionId","userId","status","inferenceResultId","score","reason","error","canRetry","creditsUsed","conversationSimulatorVersion","humanEvaluatorId","humanEvaluatorStartedAt","humanScore","humanReason","humanEvaluatorFinishedAt","failedTurns","monitorId","monitorSettledAtTurn","monitorSamplingPercentage","deletedAt","evaluatedAt","metricLegacyAt","metricDisabledAt","testCaseLegacyAt"]},"ApiToken":{"type":"object","required":["id","name","keyId","createdAt","keyPreview"],"properties":{"id":{"type":"string","example":"apiToken_abc123"},"name":{"type":"string","example":"ci-pipeline"},"keyId":{"type":"string","description":"Public identifier of the key (the uuid in gsk_<keyId>_<secret>)"},"createdAt":{"type":"string","format":"date-time"},"keyPreview":{"type":"string","description":"Display-only public head of the key (`gsk_<keyId>`). Contains no secret; safe to show truncated as `gsk_<keyId>…`.","example":"gsk_3d4d7d38-a5ec-4d9f-94a6-5a3f61db9d7d"}}},"ApiTokenWithSecret":{"type":"object","required":["id","name","keyId","createdAt","keyPreview","apiKey"],"properties":{"id":{"type":"string","example":"apiToken_abc123"},"name":{"type":"string","example":"ci-pipeline"},"keyId":{"type":"string","description":"Public identifier of the key (the uuid in gsk_<keyId>_<secret>)"},"createdAt":{"type":"string","format":"date-time"},"keyPreview":{"type":"string","description":"Display-only public head of the key (`gsk_<keyId>`). Contains no secret.","example":"gsk_3d4d7d38-a5ec-4d9f-94a6-5a3f61db9d7d"},"apiKey":{"type":"string","description":"The generated API key in `gsk_*` format. Returned only once — store it securely.","pattern":"^gsk[_-].+","example":"gsk_abc123def456"}}},"User":{"type":"object","properties":{"id":{"type":"string","example":"user_123"},"email":{"type":"string","format":"email","example":"user@example.com"},"name":{"type":"string","nullable":true,"example":"John Doe"},"role":{"type":"string","nullable":true,"enum":["ADMIN","OWNER","MEMBER"],"example":"MEMBER"},"organizationId":{"type":"string","example":"org_123"},"hasPassword":{"type":"boolean","description":"Whether the user has a password set"},"hasGoogleId":{"type":"boolean","description":"Whether the user has a linked Google account"},"hasGithubId":{"type":"boolean","description":"Whether the user has a linked GitHub account"},"hasGitlabId":{"type":"boolean","description":"Whether the user has a linked GitLab account"},"hasSamlId":{"type":"boolean","description":"Whether the user has a linked SAML account"},"hasApiKey":{"type":"boolean","description":"Whether the user currently holds at least one API token"},"analyticsConsent":{"type":"boolean","nullable":true,"example":null},"marketingConsent":{"type":"boolean","example":false},"mfaSource":{"type":"string","nullable":true,"enum":["EMAIL"],"example":null,"description":"Preferred MFA source; non-null enables MFA, null disables it. Currently only \"EMAIL\" is supported."},"firstSignInAt":{"type":"string","nullable":true,"format":"date-time"},"latestSignInAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","email","name","role","organizationId","hasPassword","hasGoogleId","hasGithubId","hasGitlabId","hasSamlId","hasApiKey","analyticsConsent","marketingConsent","mfaSource","firstSignInAt","latestSignInAt","createdAt","deletedAt"]},"Organization":{"type":"object","properties":{"id":{"type":"string","example":"org_123"},"name":{"type":"string","example":"Example Organization"},"remainingSubscriptionCredits":{"type":"integer","nullable":true,"example":1000},"extraCredits":{"type":"integer","example":500},"lastWarningAt":{"type":"string","format":"date-time","nullable":true},"warningAt":{"type":"integer","nullable":true},"stripeCustomerId":{"type":"string","nullable":true,"example":"cus_123"},"samlEntrypointUrl":{"type":"string","nullable":true},"samlEntityId":{"type":"string","nullable":true},"samlIssuerId":{"type":"string","nullable":true},"samlPublicCertificate":{"type":"string","nullable":true},"samlSignedResponse":{"type":"boolean","nullable":true},"samlSignedAssertions":{"type":"boolean","nullable":true},"samlTeamSlug":{"type":"string","nullable":true},"enforceMfa":{"type":"boolean","default":false,"description":"When true, every member of the organization must complete an MFA challenge to sign in. Settable by Owners (via update) and Admins (via create or update)."},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"Model":{"type":"object","properties":{"id":{"type":"string","example":"model_123"},"organizationId":{"type":"string","nullable":true,"example":"org_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"GPT-4"},"inputCostPerToken":{"type":"number","nullable":true,"example":0.00001},"outputCostPerToken":{"type":"number","nullable":true,"example":0.00003},"cacheReadInputTokenCost":{"type":"number","nullable":true,"example":0.000005},"cacheCreationInputTokenCost":{"type":"number","nullable":true,"example":0.000015},"inputCostPerTokenAbove128kTokens":{"type":"number","nullable":true,"example":0.00002},"outputCostPerTokenAbove128kTokens":{"type":"number","nullable":true,"example":0.00006},"tokenizerProvider":{"type":"string","nullable":true,"example":"OPENAI"},"source":{"type":"string","enum":["PREDEFINED","CUSTOM"],"nullable":true,"example":"PREDEFINED"},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"Metric":{"type":"object","properties":{"id":{"type":"string","example":"metric_123"},"metricGroupId":{"type":"string","readOnly":true,"example":"metric_123","description":"Identifier shared by every metric in the same revision family. Server-managed — derived from `parentMetricId` on create (or generated for roots). Cannot be set by the caller."},"parentMetricId":{"type":"string","nullable":true,"example":"metric_122","description":"Id of the direct parent metric. On create, providing this value turns the new metric into a revision: it joins the parent's family and (if the parent is active) flips the parent to legacy. Omit or null to create a root metric in a fresh group. On responses, this is the recorded parent edge (null for roots)."},"organizationId":{"type":"string","nullable":true,"example":"org_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"Accuracy"},"evaluationParams":{"type":"array","items":{"type":"string"},"example":["input","actualOutput","expectedOutput"],"description":"Ordered list of inference-result fields the evaluator needs (e.g. input, actualOutput, expectedOutput, retrievalContext). Determines which data the evaluation engine extracts from each inference result."},"source":{"type":"string","enum":["SELF_HOSTED","FULL_PROMPT","PARTIAL_PROMPT","HUMAN_EVALUATION","GEVAL","DEEPEVAL","DETERMINISTIC"],"nullable":true,"example":"PARTIAL_PROMPT","description":"Evaluation method for the metric. `FULL_PROMPT` is deprecated for creation — `POST /metrics` rejects it with a 400. Use `PARTIAL_PROMPT` for new AI Evaluation metrics. The value remains in the enum because existing FULL_PROMPT metrics are still returned by reads and filters."},"judgePrompt":{"type":"string","nullable":true,"example":"Evaluate the accuracy of the response"},"tags":{"type":"array","items":{"type":"string"},"example":["accuracy","quality"]},"description":{"type":"string","nullable":true,"example":"Measures the accuracy of responses"},"documentationUrl":{"type":"string","nullable":true,"example":"https://docs.example.com/metrics/accuracy"},"evaluatorModelName":{"type":"string","nullable":true,"example":"GPT-4"},"areEvalParamsTop":{"type":"boolean","nullable":true,"description":"When true, evaluationParams are injected at the top level of the evaluator prompt instead of nested inside the conversation context."},"isBeingOptimized":{"type":"boolean","readOnly":true,"description":"Whether the metric is currently being optimized."},"specificationIds":{"type":"array","items":{"type":"string"},"example":["spec_123"]},"userGroupIds":{"type":"array","items":{"type":"string"},"example":["ug_123"]},"createdAt":{"type":"string","format":"date-time"},"legacyAt":{"type":"string","format":"date-time","nullable":true,"readOnly":true,"description":"Earliest non-null of this metric's own legacy date and its evaluator model's `unselectableAt`, so a model no longer selectable makes every metric linked to it report as legacy even though the metric row itself is untouched. Present only once that date has passed: a scheduled future cutoff reports null, because the metric is still active until then. Unlike `disabledAt`, this field never carries a future date."},"disabledAt":{"type":"string","format":"date-time","nullable":true,"readOnly":true,"description":"Earliest non-null of this metric's own disabled date and its evaluator model's `disabledAt` — a disabled model makes every metric linked to it report as disabled even though the metric row itself is untouched."}}},"CompatibleMetric":{"type":"object","description":"Metric annotated with compatibility against the evaluation context (product metadata + conversation endpoint connection output mapping). Trace-dependent and runtime-only params are out of scope and treated as always satisfied.","properties":{"id":{"type":"string","example":"metric_123"},"name":{"type":"string","example":"Accuracy"},"source":{"type":"string","enum":["SELF_HOSTED","FULL_PROMPT","PARTIAL_PROMPT","HUMAN_EVALUATION","GEVAL","DEEPEVAL","DETERMINISTIC"],"nullable":true,"example":"PARTIAL_PROMPT","description":"Evaluation method for the metric. `FULL_PROMPT` is deprecated for creation — `POST /metrics` rejects it with a 400. Use `PARTIAL_PROMPT` for new AI Evaluation metrics. The value remains in the enum because existing FULL_PROMPT metrics are still returned by reads and filters."},"description":{"type":"string","nullable":true,"example":"Measures the accuracy of responses"},"isCompatible":{"type":"boolean","description":"Whether the metric can be satisfied by the resolved product metadata and conversation endpoint connection output mapping."},"incompatibilityReason":{"type":"string","nullable":true,"description":"Human-readable explanation of why the metric is incompatible. Non-null iff `isCompatible === false`.","example":"Missing required parameters: product_capabilities, retrieval_context"},"relevance":{"type":"string","enum":["linked","matching","none"],"description":"How relevant the metric is to the tests the evaluation runs against. `linked`: linked to a specification of one of those tests. `matching`: linked to a same-product specification whose testType matches one of those tests. `none`: neither, or no test context was provided.","example":"linked"}},"required":["id","name","isCompatible","relevance"]},"AnalyticsInsightFlag":{"type":"object","description":"A single deterministic red flag / proactive insight computed over the analytics aggregation. Contextual fields are populated only when they apply to the flag type.","properties":{"type":{"type":"string","enum":["low_metric_score","low_specification_score","coverage_gap","metric_degradation","metric_improvement","cost_outlier","latency_outlier"],"example":"low_metric_score"},"severity":{"type":"string","enum":["critical","warning","info","positive"],"example":"critical"},"title":{"type":"string","example":"Low score: Faithfulness"},"description":{"type":"string","example":"Faithfulness scored 42% on v3; 12 of 78 evaluations scored zero (15.4%)."},"testType":{"type":"string","nullable":true,"example":"QUALITY"},"versionId":{"type":"string","nullable":true,"example":"ver_123"},"versionName":{"type":"string","nullable":true,"example":"v3"},"metricId":{"type":"string","nullable":true,"example":"metric_123"},"metricName":{"type":"string","nullable":true,"example":"Faithfulness"},"specificationId":{"type":"string","nullable":true,"example":"spec_123"},"currentValue":{"type":"number","nullable":true,"example":42},"comparisonValue":{"type":"number","nullable":true,"example":71},"unit":{"type":"string","nullable":true,"enum":["%","ms","USD","tokens"],"example":"%"},"failureRate":{"type":"number","nullable":true,"description":"Percentage (0-100) of the metric's scored evaluations that scored exactly zero within the request filters; null when the stats were unavailable.","example":15.4},"evaluationCount":{"type":"number","nullable":true,"description":"Scored evaluations behind failureRate; null when the stats were unavailable.","example":78}},"required":["type","severity","title","description"]},"AnalyticsInsights":{"type":"object","description":"Single-version analytics insights: deterministic flags plus a fail-open LLM-generated narrative summary (the narrative is omitted when the request sets `includeNarrative=false`).","properties":{"productId":{"type":"string","example":"prod_123"},"versionId":{"type":"string","example":"ver_123"},"versionName":{"type":"string","example":"v3"},"status":{"type":"string","enum":["all_good","flags_present"],"example":"flags_present"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsInsightFlag"}},"narrative":{"type":"string","nullable":true,"description":"LLM-generated narrative summary, or null when generation was skipped (`includeNarrative=false` or no flags) or failed.","example":"Faithfulness dropped sharply on v3 and two specifications still have no coverage."},"narrativeGeneratedByAi":{"type":"boolean","description":"True when the narrative was successfully produced by the LLM; false otherwise (including when `includeNarrative=false`)."}},"required":["productId","versionId","versionName","status","flags","narrativeGeneratedByAi"]},"AnalyticsInsightsComparison":{"type":"object","description":"Cross-version analytics comparison insights: deterministic flags plus a fail-open LLM-generated narrative summary (the narrative is omitted when the request sets `includeNarrative=false`).","properties":{"productId":{"type":"string","example":"prod_123"},"versionIds":{"type":"array","items":{"type":"string"},"example":["ver_122","ver_123"]},"status":{"type":"string","enum":["all_good","flags_present"],"example":"flags_present"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsInsightFlag"}},"narrative":{"type":"string","nullable":true,"description":"LLM-generated narrative summary, or null when generation was skipped (`includeNarrative=false` or no flags) or failed.","example":"Faithfulness regressed from v2 to v3 while latency on v3 is 1.6× the cheapest version."},"narrativeGeneratedByAi":{"type":"boolean","description":"True when the narrative was successfully produced by the LLM; false otherwise (including when `includeNarrative=false`)."}},"required":["productId","versionIds","status","flags","narrativeGeneratedByAi"]},"Session":{"type":"object","properties":{"id":{"type":"string","example":"session_123"},"customId":{"type":"string","nullable":true,"example":"custom_session_123"},"versionId":{"type":"string","example":"ver_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"testCaseId":{"type":"string","nullable":true,"example":"tc_123"},"context":{"type":"object","nullable":true,"description":"Structured context data. For plain text context, format is { value: \"...\" }","example":{"value":"Session context information"}},"stoppingReason":{"type":"string","nullable":true,"example":"GOAL_ACHIEVED"},"recordingUri":{"type":"string","nullable":true,"description":"Canonical storage URI of the full-call recording for a telephony-evaluation session. Null for non-telephony sessions or before the recording is processed. Resolve to a playable URL via GET /storage?uri=.","example":"s3://galtea-bucket/audio/org_123/session_abc-recording.mp3"},"error":{"type":"string","nullable":true,"example":"External API responded with HTTP 422: Unprocessable Entity — {\"detail\":\"model not found\"}"},"status":{"type":"string","enum":["PENDING","COMPLETED","FAILED"],"example":"PENDING"},"isProduction":{"type":"boolean","description":"True when the session represents real production traffic (no associated test case).","example":false},"metadata":{"type":"object","nullable":true,"example":{"key":"value"}},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"SessionInput":{"type":"object","description":"Session creation input. `versionId` is optional: when omitted, provide `productId` and the API reuses the product's latest version (creating a default first version if the product has none). One of `versionId` or `productId` is required. `testCaseId` and `isProduction` are independent: a session can be production (no testCaseId), test-driven non-production (testCaseId set, isProduction defaults to false), or externally-ingested non-production (no testCaseId, isProduction explicitly false — typical for imported traces). The only forbidden combination is `testCaseId` set together with `isProduction=true`. When `testCaseId` is set, `context` is rejected because it would be derived from the test case.","properties":{"versionId":{"type":"string","description":"Version ID to create the session for. Optional when productId is provided; one of versionId or productId is required.","example":"ver_123"},"productId":{"type":"string","description":"Product to anchor the session when versionId is omitted. The API reuses the product's latest version or creates a default one. Ignored when versionId is provided.","example":"prod_123"},"customId":{"type":"string","description":"Optional caller-defined identifier for the session","example":"my-session-1"},"testCaseId":{"type":"string","description":"Test case to link this session to. Forbidden when isProduction=true. Defaults to omitted, in which case isProduction defaults to true.","example":"tc_123"},"isProduction":{"type":"boolean","description":"Whether the session represents real production traffic. Defaults to true when testCaseId is omitted and false when testCaseId is set. May be set explicitly to false without a testCaseId for externally-ingested sessions (e.g. trace imports)."},"context":{"oneOf":[{"type":"string"},{"type":"object","additionalProperties":true}],"description":"Additional context for the session. Accepts a plain string or a structured JSON object. Forbidden when testCaseId is set (the context is derived from the test case)."},"metadata":{"type":"object","description":"Arbitrary key-value metadata","example":{"key":"value"}},"status":{"type":"string","enum":["PENDING","COMPLETED","FAILED"],"default":"PENDING","description":"Initial session status. Defaults to PENDING (open, accepts new turns); the session closes on an explicit finish or the product auto-close sweep (#3384)."}}},"InferenceResult":{"type":"object","properties":{"id":{"type":"string","example":"ir_123"},"sessionId":{"type":"string","example":"session_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"index":{"type":"integer","example":0,"description":"Order index within the session"},"status":{"type":"string","enum":["PENDING","GENERATED","FAILED","SKIPPED"],"example":"PENDING"},"error":{"type":"string","nullable":true,"description":"Error message explaining why this inference result failed or was skipped","example":null},"input":{"type":"object","nullable":true,"description":"Structured input data. For plain text input, format is { user_message: \"...\" }","example":{"user_message":"User input text"}},"actualOutput":{"oneOf":[{"type":"string"},{"type":"object"}],"nullable":true,"description":"The agent turn output. Plain text by default (the scored scalar). For voice turns, an envelope { assistant_message, content: [{ type, uri, transcript }] } carrying audio parts — the scored scalar stays the canonical transcript.","example":"Model response"},"latency":{"type":"integer","nullable":true,"example":150},"inputTokens":{"type":"integer","nullable":true,"example":100},"outputTokens":{"type":"integer","nullable":true,"example":50},"cacheReadInputTokens":{"type":"integer","nullable":true,"example":20},"tokens":{"type":"integer","nullable":true,"example":150,"description":"Total tokens"},"costPerInputToken":{"type":"number","nullable":true,"example":0.00001},"costPerOutputToken":{"type":"number","nullable":true,"example":0.00003},"costPerCacheReadInputToken":{"type":"number","nullable":true,"example":0.000005},"cost":{"type":"number","nullable":true,"example":0.001},"creditsUsed":{"type":"integer","nullable":true,"example":1},"conversationSimulatorVersion":{"type":"string","nullable":true,"example":"1.0.0"},"traceId":{"type":"string","nullable":true,"example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4","description":"W3C trace ID for the root span created during direct inference. The same trace ID is propagated to the user endpoint via the traceparent header."},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true},"comments":{"type":"array","description":"Free-form reviewer annotations on this turn, oldest first.","items":{"$ref":"#/components/schemas/Comment"}}}},"Trace":{"type":"object","properties":{"id":{"type":"string","example":"trace_123"},"inferenceResultId":{"type":"string","example":"ir_123"},"name":{"type":"string","example":"fetch_user_data"},"type":{"type":"string","enum":["SPAN","GENERATION","EVENT","AGENT","TOOL","CHAIN","RETRIEVER","EVALUATOR","EMBEDDING","GUARDRAIL"],"nullable":true,"example":"TOOL"},"description":{"type":"string","nullable":true,"example":"Fetches user data from the database by ID","description":"Human-readable description of the operation. Maximum 1MB."},"inputData":{"type":"object","nullable":true,"example":{"user_id":"123"},"description":"Input parameters passed to the operation"},"outputData":{"oneOf":[{"type":"object"},{"type":"string"}],"nullable":true,"example":{"name":"John Doe","email":"john@example.com"},"description":"Result returned by the operation. Usually an object; a plain string for retrieval-context traces"},"error":{"type":"string","nullable":true,"example":"Connection timeout","description":"Error message if failed"},"latencyMs":{"type":"number","nullable":true,"example":45.5,"description":"Execution time in milliseconds"},"metadata":{"type":"object","nullable":true,"example":{"model":"gpt-4","temperature":0.7},"description":"Additional custom metadata"},"parentTraceId":{"type":"string","nullable":true,"example":"trace_parent_123","description":"ID of parent trace for hierarchical relationships"},"startTime":{"type":"string","format":"date-time","nullable":true},"endTime":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"Specification":{"type":"object","properties":{"id":{"type":"string","example":"spec_123"},"productId":{"type":"string","example":"prod_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"Accurate query responses"},"description":{"type":"string","example":"Product must respond accurately to user queries"},"type":{"type":"string","enum":["CAPABILITY","INABILITY","POLICY"],"example":"CAPABILITY"},"testType":{"type":"string","nullable":true,"enum":["QUALITY","RED_TEAMING","SCENARIOS"],"example":"QUALITY","description":"Only applicable for POLICY specifications. Must be null for CAPABILITY and INABILITY."},"testVariant":{"type":"string","nullable":true,"example":"rag","description":"Only applicable for POLICY specifications. QUALITY: rag, entity_extraction, summarization, classification, translation, correction, other. RED_TEAMING: data_leakage, financial_attacks, illegal_activities, misuse, toxicity, custom."},"useForTestAlignment":{"type":"boolean","example":true},"metricIds":{"type":"array","items":{"type":"string"},"example":["metric_123"]},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"SpecificationSuggestion":{"type":"object","properties":{"status":{"type":"string","enum":["new","updated","contradictory"],"example":"updated","description":"new = a fresh addition. updated = refines/extends an existing specification. contradictory = conflicts with an existing specification."},"name":{"type":"string","example":"Refuses system-prompt disclosure"},"description":{"type":"string","example":"Must not reveal internal system prompts under social engineering"},"type":{"type":"string","enum":["CAPABILITY","INABILITY","POLICY"],"example":"POLICY"},"testType":{"type":"string","nullable":true,"enum":["QUALITY","RED_TEAMING","SCENARIOS",null],"example":"RED_TEAMING","description":"Only applicable for POLICY specifications. Null for CAPABILITY and INABILITY."},"testVariant":{"type":"string","nullable":true,"example":"data_leakage","description":"Only applicable for POLICY specifications."},"existingSpecification":{"type":"object","nullable":true,"properties":{"id":{"type":"string","example":"spec_123"},"name":{"type":"string","example":"Refuses system-prompt disclosure"},"description":{"type":"string","example":"Must not reveal internal system prompts"},"type":{"type":"string","enum":["CAPABILITY","INABILITY","POLICY"],"example":"POLICY"},"testType":{"type":"string","nullable":true,"enum":["QUALITY","RED_TEAMING","SCENARIOS",null],"example":"RED_TEAMING"},"testVariant":{"type":"string","nullable":true,"example":"data_leakage"}},"required":["id","name","description","type","testType","testVariant"],"description":"The existing specification this suggestion updates or contradicts. Null for `new` suggestions."},"rationale":{"type":"string","nullable":true,"example":"Adds social-engineering scope to the existing disclosure policy","description":"A brief explanation of why this status was chosen. May be null."}},"required":["status","name","description","type","testType","testVariant","existingSpecification","rationale"]},"UserGroup":{"type":"object","properties":{"id":{"type":"string","example":"ug_123"},"organizationId":{"type":"string","example":"org_123"},"name":{"type":"string","example":"QA Team"},"type":{"type":"string","enum":["EVALUATOR"],"example":"EVALUATOR"},"description":{"type":"string","nullable":true,"example":"Quality assurance team"},"createdAt":{"type":"string","format":"date-time"},"userIds":{"type":"array","items":{"type":"string"},"example":["user_123"]},"metricIds":{"type":"array","items":{"type":"string"},"example":["metric_123"]}}},"EvaluatorModel":{"type":"object","properties":{"name":{"type":"string","example":"gpt-4o"},"disabledAt":{"type":"string","format":"date-time","nullable":true},"unselectableAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"Error":{"type":"object","properties":{"error":{"type":"string","example":"Error type"},"message":{"type":"string","example":"Error message description"}}},"TraceImportResponse":{"type":"object","properties":{"jobId":{"type":"string","description":"Id of the BullMQ job processing the import. Poll `GET /jobs/{jobId}/status` for state.","example":"job_abc123"},"versionId":{"type":"string","description":"Id of the Version the imported sessions will belong to: the versionId sent in the request, or the version resolved from productId (issue #3011).","example":"ver_123"}},"required":["jobId","versionId"]},"EndpointConnection":{"type":"object","required":["productId","name","url","httpMethod","authType","inputTemplate","outputMapping"],"properties":{"id":{"type":"string","example":"ec_123"},"productId":{"type":"string","example":"prod_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"My API Connection"},"url":{"type":"string","example":"https://api.example.com/v1/chat/completions"},"httpMethod":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"example":"POST"},"authType":{"type":"string","enum":["NONE","BEARER","API_KEY","BASIC"],"example":"BEARER"},"hasAuthToken":{"type":"boolean","description":"Whether an auth token is configured (token value is not exposed)"},"username":{"type":"string","nullable":true,"description":"Username for Basic auth"},"hasPassword":{"type":"boolean","description":"Whether a password is configured (password value is not exposed)"},"headers":{"type":"object","nullable":true,"additionalProperties":{"type":"string"},"example":{"Content-Type":"application/json"}},"inputTemplate":{"type":"string","nullable":true,"description":"Jinja2/Nunjucks template for request body. Must contain {{ input.user_message }} placeholder.","example":"{\"prompt\": \"{{ input.user_message }}\"}"},"inputSchema":{"type":"object","nullable":true,"description":"Optional JSON Schema (draft 2020-12) defining the structure of input fields, their types, and valid values. Must have type \"object\" with a \"properties\" key.","example":{"type":"object","properties":{"user_message":{"type":"string","description":"The main user message to the agent"},"reasoning_level":{"type":"string","enum":["low","medium","high"],"description":"How much reasoning the agent should apply"},"topic":{"type":"string","enum":["billing","shipping","returns","account"],"description":"Conversation topic"},"customer_id":{"type":"string","pattern":"^C-\\d{3,6}$","description":"Customer identifier"}},"required":["user_message"]}},"outputMapping":{"type":"object","nullable":true,"additionalProperties":{"type":"string"},"description":"JSONPath expressions to extract values from API response. Must include \"output\" key.","example":{"output":"$.choices[0].message.content"}},"type":{"type":"string","enum":["INITIALIZATION","CONVERSATION","FINALIZATION"],"example":"CONVERSATION"},"timeout":{"type":"integer","nullable":true,"minimum":1,"maximum":120,"default":15,"example":15,"description":"Per-attempt request timeout in seconds. Unset applies the default (15). Capped server-side at 120 seconds."},"rateLimit":{"type":"integer","nullable":true,"minimum":1,"example":60,"description":"Maximum requests per minute. Unset (null) means no rate limit."},"retryEnabled":{"type":"boolean","default":true,"description":"Whether automatic retry is enabled for failed requests"},"retryMaxAttempts":{"type":"integer","nullable":true,"minimum":0,"maximum":10,"default":1,"description":"Maximum number of retry attempts (applied when retryEnabled is true). 0 is only valid when retryEnabled is false; with retry enabled the minimum is 1."},"retryInitialDelayMs":{"type":"integer","nullable":true,"minimum":0,"default":1000,"description":"Initial delay in milliseconds before first retry"},"retryBackoffStrategy":{"type":"string","nullable":true,"enum":["FIXED","EXPONENTIAL","LINEAR"],"default":"EXPONENTIAL","description":"Strategy for increasing delay between retries"},"retryMaxDelayMs":{"type":"integer","nullable":true,"minimum":0,"maximum":60000,"default":3000,"description":"Maximum delay between retry attempts, in milliseconds. Capped server-side at 60000 (60 seconds) to bound retry blast radius."},"retryableStatusCodes":{"type":"array","items":{"type":"integer","minimum":100,"maximum":599},"default":[429,500,502,503,504],"description":"HTTP status codes that should trigger a retry"},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"PhoneConnection":{"type":"object","required":["productId","name","phoneNumber"],"properties":{"id":{"type":"string","example":"phoneConnection_123"},"productId":{"type":"string","example":"prod_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"Support line"},"phoneNumber":{"type":"string","description":"The phone number Galtea dials, in E.164 format.","example":"+14155552671"},"agentSpeaksFirst":{"type":"boolean","default":false,"description":"Whether the voice agent opens the conversation once the call connects. `false` (default) means the simulated caller speaks first; `true` suits interviewer-style agents that greet first.","example":false},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"WebRtcConnection":{"type":"object","required":["productId","name","apiKey","agentName"],"properties":{"id":{"type":"string","example":"webRtcConnection_123"},"productId":{"type":"string","example":"prod_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"Support agent (WebRTC)"},"apiKey":{"type":"string","writeOnly":true,"description":"Pipecat Cloud PUBLIC API key (`pk_...`) Galtea uses to provision a room via the runtime `/start` call. This is NOT the `pcc_pat_` Personal Access Token used to deploy agents. Encrypted at rest and never returned; read `hasApiKey` to know whether one is set. On update, omit it to keep the stored key.","example":"pk_..."},"hasApiKey":{"type":"boolean","readOnly":true,"description":"Whether a Pipecat Cloud API key is stored for this connection.","example":true},"agentName":{"type":"string","description":"Name of your deployed Pipecat Cloud agent. Must match that agent's deployed name exactly. Galtea passes it to the Pipecat Cloud `/start` call to launch the session; if no deployed agent has this name, `/start` fails.","example":"my-voice-agent"},"agentSpeaksFirst":{"type":"boolean","default":false,"description":"Whether the voice agent opens the conversation once the session connects. `false` (default) means the simulated caller speaks first; `true` suits interviewer-style agents that greet first.","example":false},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"Monitor":{"type":"object","required":["productId","name","metricGroupIds"],"properties":{"id":{"type":"string","example":"monitor_123"},"productId":{"type":"string","example":"prod_123"},"versionId":{"type":"string","nullable":true,"description":"Optional version to narrow the monitor to. When null the monitor watches the whole product.","example":"version_123"},"userId":{"type":"string","nullable":true,"example":"user_123"},"name":{"type":"string","example":"Production quality watch"},"metricGroupIds":{"type":"array","items":{"type":"string"},"description":"Metric families (Metric.metricGroupId) the monitor scores with. The monitor binds the family, not a specific revision, so revising a metric is picked up automatically without editing the monitor.","example":["metricGroup_123"]},"samplingPercentage":{"type":"number","default":10,"minimum":0,"exclusiveMinimum":true,"maximum":100,"description":"Percentage of production sessions to evaluate (greater than 0, at most 100).","example":10},"monthlyCreditCap":{"type":"integer","nullable":true,"minimum":1,"description":"Optional monthly credit ceiling for this monitor. When set it must be a positive integer; it may exceed the organization monthly allocation (spend is clamped to the available balance). Null means uncapped.","example":500},"filterQuery":{"type":"string","nullable":true,"maxLength":500,"description":"Optional content gate. Comma-separated terms; a session matches when at least one turn whose chosen target (filterTarget) contains ANY term (case-insensitive). Only matching sessions are sampled and evaluated; other sessions are skipped, spending no credits. Max 500 chars. Must be set together with filterTarget. Null means watch every session.","example":"refund, cancel, chargeback"},"filterTarget":{"type":"string","enum":["INPUT","OUTPUT","EITHER"],"nullable":true,"description":"Which side of a turn filterQuery is matched against: INPUT (the user turn), OUTPUT (the agent turn), or EITHER. Must be set together with filterQuery.","example":"EITHER"},"excludeQuery":{"type":"string","nullable":true,"maxLength":500,"description":"Optional exclude gate. Comma-separated terms; a session is dropped when at least one turn whose chosen target (excludeTarget) contains ANY term (case-insensitive). Applied on top of filterQuery: a session is watched only when it passes filterQuery (if set) AND is not hit by excludeQuery. Max 500 chars. Must be set together with excludeTarget. Null means exclude nothing.","example":"test, internal"},"excludeTarget":{"type":"string","enum":["INPUT","OUTPUT","EITHER"],"nullable":true,"description":"Which side of a turn excludeQuery is matched against: INPUT (the user turn), OUTPUT (the agent turn), or EITHER. Must be set together with excludeQuery.","example":"EITHER"},"status":{"type":"string","enum":["ACTIVE","PAUSED","CAPPED","NO_CREDITS","FAILING"],"default":"ACTIVE","description":"Users may set ACTIVE or PAUSED; CAPPED, NO_CREDITS and FAILING are system-set by the scanner and rejected on user writes.","example":"ACTIVE"},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"MonitorScorePoint":{"type":"object","description":"Sampling-weighted score over a set of scored sessions. Below 30 scored sessions confidenceInterval is null and collectingData is true; score stays the point estimate (null only when nothing scored).","required":["scoredSessions","score","confidenceInterval","collectingData"],"properties":{"scoredSessions":{"type":"integer","example":42},"score":{"type":"number","nullable":true,"description":"Weighted mean score (0-1).","example":0.73},"confidenceInterval":{"type":"object","nullable":true,"description":"95% confidence interval, present only at 30 or more scored sessions.","required":["lower","upper"],"properties":{"lower":{"type":"number","example":0.68},"upper":{"type":"number","example":0.78}}},"collectingData":{"type":"boolean","example":false}}},"MonitorResults":{"type":"object","description":"Aggregated results for a monitor over a trailing window, computed only from the monitor's own evaluations.","required":["monitorId","range","metrics","worstMetric","markers","spend","sessions"],"properties":{"monitorId":{"type":"string","example":"monitor_123"},"range":{"type":"object","required":["from","to","bucketDays"],"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"bucketDays":{"type":"integer","example":1}}},"metrics":{"type":"array","description":"One score series per bound metric family.","items":{"type":"object","required":["metricGroupId","name","headline","buckets"],"properties":{"metricGroupId":{"type":"string","example":"metricGroup_123"},"name":{"type":"string","example":"Accuracy"},"headline":{"$ref":"#/components/schemas/MonitorScorePoint"},"buckets":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/MonitorScorePoint"},{"type":"object","required":["bucket"],"properties":{"bucket":{"type":"string","format":"date-time"}}}]}}}}},"worstMetric":{"type":"object","nullable":true,"description":"Lowest-scoring metric family over the range. Never an average across metrics.","allOf":[{"$ref":"#/components/schemas/MonitorScorePoint"},{"type":"object","required":["metricGroupId","name"],"properties":{"metricGroupId":{"type":"string","example":"metricGroup_123"},"name":{"type":"string","example":"Custom judge"}}}]},"markers":{"type":"object","required":["metricRevisions","samplingChanges"],"properties":{"metricRevisions":{"type":"array","items":{"type":"object","required":["metricGroupId","name","metricId","at"],"properties":{"metricGroupId":{"type":"string"},"name":{"type":"string"},"metricId":{"type":"string"},"at":{"type":"string","format":"date-time"}}}},"samplingChanges":{"type":"array","description":"Effective sampling rate over the range. The FIRST element is the baseline (the rate already in effect when the range opens), not a change; every later element is a real change. Skip the first when drawing \"sampling changed\" markers.","items":{"type":"object","required":["at","samplingPercentage"],"properties":{"at":{"type":"string","format":"date-time"},"samplingPercentage":{"type":"number","example":10}}}}}},"spend":{"type":"object","required":["spentCredits","pendingCredits","capCredits","cycleStart"],"properties":{"spentCredits":{"type":"integer","example":240},"pendingCredits":{"type":"integer","example":12},"capCredits":{"type":"integer","nullable":true,"example":500},"cycleStart":{"type":"string","format":"date-time","nullable":true}}},"sessions":{"type":"object","required":["scored","waiting"],"properties":{"scored":{"type":"array","description":"Scored sessions, most-recent first (capped at 200).","items":{"type":"object","required":["sessionId","evaluatedAt","settledAtTurn","description"],"properties":{"sessionId":{"type":"string"},"evaluatedAt":{"type":"string","format":"date-time"},"settledAtTurn":{"type":"integer","nullable":true},"description":{"type":"string","example":"Evaluated at turn 6"}}}},"waiting":{"type":"array","description":"Production sessions attached to the monitor not yet closed (capped at 100).","items":{"type":"object","required":["sessionId","lastTurnAt","minutesSinceLastTurn","description"],"properties":{"sessionId":{"type":"string"},"lastTurnAt":{"type":"string","format":"date-time"},"minutesSinceLastTurn":{"type":"integer","example":2},"description":{"type":"string","example":"Waiting: last turn 2 min ago"}}}}}}}},"MonitorMatchPreview":{"type":"object","description":"Read-only preview of how many and which recent past sessions a candidate monitor content filter and sampling percentage would select. No evaluations run and no credits are spent.","required":["range","candidateCount","matchCount","sampledCount","approximateSampling","sampledSessions"],"properties":{"range":{"type":"object","required":["from","to"],"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"}}},"candidateCount":{"type":"integer","description":"Recent closed production sessions considered (bounded by the window and an internal cap).","example":500},"matchCount":{"type":"integer","description":"Sessions whose content matched the candidate filter (exact; a null filter matches every candidate).","example":120},"sampledCount":{"type":"integer","description":"Matched sessions that also fell in the sampling fraction.","example":12},"approximateSampling":{"type":"boolean","description":"True for a create preview (no monitorId): the sampled subset is representative, computed from a placeholder seed. The match count is always exact.","example":true},"sampledSessions":{"type":"array","description":"The would-be-selected sessions, most-recent first (capped at 100).","items":{"type":"object","required":["sessionId","versionId","createdAt","turnCount","matchedText"],"properties":{"sessionId":{"type":"string","example":"session_123"},"versionId":{"type":"string","example":"version_123"},"createdAt":{"type":"string","format":"date-time"},"turnCount":{"type":"integer","example":4},"matchedText":{"type":"string","description":"A short snippet of the matched content (centered on the first matched term with a content filter) or the first turn input (without a filter). Capped at ~160 characters plus ellipsis markers.","example":"I would like a refund for my last order because it arrived damaged…"}}}}}},"ParseCurlEndpointConnectionResult":{"type":"object","required":["parsed","errors"],"description":"Result of parsing a raw cURL command. `parsed` is best-effort and always present (even when `errors` is non-empty); `errors` lists structured reasons the command could not be fully parsed.","properties":{"parsed":{"type":"object","properties":{"url":{"type":"string","nullable":true,"example":"https://api.example.com/v1/chat"},"httpMethod":{"type":"string","nullable":true,"enum":["GET","POST","PUT","PATCH","DELETE"],"example":"POST"},"headers":{"type":"object","nullable":true,"additionalProperties":{"type":"string"},"example":{"Content-Type":"application/json"}},"authType":{"type":"string","nullable":true,"enum":["NONE","BEARER","API_KEY","BASIC"],"example":"BEARER"},"authToken":{"type":"string","nullable":true,"description":"Bearer token or API key extracted from the command (when present)."},"username":{"type":"string","nullable":true,"description":"Basic-auth username (when present)."},"password":{"type":"string","nullable":true,"description":"Basic-auth password (when present)."},"body":{"type":"string","nullable":true,"description":"Raw request body, verbatim (when present)."},"inputTemplate":{"type":"string","nullable":true,"description":"Best-effort Jinja2 input template derived from a JSON body. Null when the body is absent or not JSON.","example":"{\"messages\":[{\"role\":\"user\",\"content\":\"{{ input.user_message }}\"}]}"},"inputTemplateGeneratedByAi":{"type":"boolean","description":"True when `inputTemplate` was produced by the LLM enrichment pass (placing the full placeholder vocabulary) rather than the deterministic single-leaf heuristic. Lets the caller badge the field as AI-generated vs auto-filled.","example":true},"name":{"type":"string","nullable":true,"description":"Suggested connection name. A deterministic host-based default (`{host} {Type} Connection`) for every type, upgraded by the LLM enrichment pass for CONVERSATION using the URL and the optional `productName`.","example":"Acme Support — OpenAI Chat"},"nameGeneratedByAi":{"type":"boolean","description":"True when `name` was produced by the LLM enrichment pass rather than the deterministic host-based floor. Lets the caller badge the field as AI-generated vs auto-filled.","example":true}}},"errors":{"type":"array","items":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["NOT_CURL","NO_URL","UNTERMINATED_QUOTE","BODY_NOT_JSON","DANGLING_FLAG"],"example":"BODY_NOT_JSON"},"message":{"type":"string","example":"The request body is not valid JSON, so no input template could be derived. The raw body was kept."}}}}}},"TraceImportUpload":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The Langfuse trace export (JSON/JSONL/CSV). Max 25MB."},"versionId":{"type":"string","description":"Id of the Version the imported sessions belong to. Optional: when omitted, provide productId and the API reuses the product's latest version (creating a default first version if the product has none).","example":"ver_123"},"productId":{"type":"string","description":"Id of the Product to anchor the import when versionId is omitted. Ignored when versionId is provided.","example":"prod_123"},"isProduction":{"type":"string","enum":["true","false"],"description":"Whether the imported sessions are production traffic. Defaults to \"true\"."}},"required":["file"]},"TraceImportText":{"type":"object","properties":{"text":{"type":"string","minLength":1,"description":"The Langfuse trace export as a JSON string."},"versionId":{"type":"string","description":"Id of the Version the imported sessions belong to. Optional: when omitted, provide productId and the API reuses the product's latest version (creating a default first version if the product has none).","example":"ver_123"},"productId":{"type":"string","description":"Id of the Product to anchor the import when versionId is omitted. Ignored when versionId is provided.","example":"prod_123"},"originalFilename":{"type":"string","description":"Optional filename to associate with the upload. Defaults to \"pasted_trace.json\"."},"isProduction":{"type":"boolean","description":"Whether the imported sessions are production traffic. Defaults to true."}},"required":["text"]},"BuildInfo":{"type":"object","properties":{"version":{"type":"string","description":"Platform release version this service's running image was built for, baked in at build time. `dev` when unset. A service not rebuilt in a release reports its previous version.","example":"4.39.0"},"commit":{"type":"string","description":"Git commit the running image was built from.","example":"a648b3218e1c2f3a4b5c6d7e8f9a0b1c2d3e4f5a"},"buildDate":{"type":"string","description":"When the running image was built.","example":"2026-07-27T00:00:00.000Z"}},"required":["version","commit","buildDate"]},"ServiceBuildInfo":{"type":"object","properties":{"name":{"type":"string","description":"Downstream service identifier, e.g. `evaluator`, `report-generator`.","example":"evaluator"},"status":{"type":"string","enum":["ok","unreachable","not_implemented","not_configured"],"description":"`ok`: build info returned normally. `unreachable`: the service did not respond in time, the request failed, or it answered with a body that does not match the build-info shape. `not_implemented`: the service answered 404, meaning it has not shipped its own `/build-info` route yet. `not_configured`: this deployment has no URL set for the service (only possible for services not validated at startup).","example":"ok"},"version":{"type":"string","description":"Only present when `status` is `ok`.","example":"4.39.0"},"commit":{"type":"string","description":"Only present when `status` is `ok`."},"buildDate":{"type":"string","description":"Only present when `status` is `ok`."}},"required":["name","status"]},"BuildInfoServices":{"type":"object","properties":{"api":{"$ref":"#/components/schemas/BuildInfo"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServiceBuildInfo"}}},"required":["api","services"]},"Comment":{"type":"object","properties":{"id":{"type":"string","example":"comment_123"},"inferenceResultId":{"type":"string","example":"inferenceResult_123"},"text":{"type":"string","example":"Agent hallucinated the price."},"tags":{"type":"array","items":{"type":"string"},"example":["hallucination","tone"]},"userId":{"type":"string","nullable":true,"example":"user_123"},"userName":{"type":"string","nullable":true,"example":"John Doe"},"userEmail":{"type":"string","nullable":true,"format":"email","example":"user@example.com"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","inferenceResultId","text","tags","userId","userName","userEmail","createdAt"]},"CreateFromTestCasesBody":{"type":"object","properties":{"newTestCaseId":{"type":"string","minLength":1,"example":"testCase_123","description":"The new test case revision to replay onto. Must be the active head of its family."},"testCaseGroupId":{"type":"string","minLength":1,"example":"group_123","description":"The revision family whose past evaluations are replayed. Must match the test case."},"productIds":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"example":["prod_1","prod_2"],"description":"Products whose past evaluations are replayed."}},"required":["newTestCaseId","testCaseGroupId","productIds"]},"ReplayFromTestCasesResult":{"type":"object","properties":{"scheduled":{"type":"integer","description":"Count of (version, metric) pairs dispatched for fresh inference"},"skipped":{"type":"integer","description":"Count of (version, metric) pairs skipped (dispatch failures)"},"errors":{"type":"array","items":{"type":"string"},"description":"Per-version dispatch error messages"}},"required":["scheduled","skipped","errors"]},"GenerateSpecConfigBody":{"type":"object","properties":{"description":{"type":"string","minLength":1,"maxLength":5000,"example":"no swearing pls","description":"The rough, brief, or already-written specification description (max 5000 characters)"},"productId":{"type":"string","example":"prod_123","description":"Optional product ID for additional context"}},"required":["description"]},"SpecConfigResponse":{"type":"object","properties":{"name":{"type":"string","description":"The AI-written short specification name"},"description":{"type":"string","description":"The AI-written specification description, rewritten from the input"},"type":{"type":"string","enum":["CAPABILITY","INABILITY","POLICY"],"description":"Suggested specification type"},"testType":{"type":"string","nullable":true,"enum":["QUALITY","RED_TEAMING","SCENARIOS",null],"description":"Suggested test type (POLICY only; null otherwise)"},"testVariant":{"type":"string","nullable":true,"description":"Suggested test variant (QUALITY and RED_TEAMING test types only; null otherwise)"}},"required":["name","description","type","testType","testVariant"]},"GenerateProductConfigBody":{"type":"object","properties":{"productSpecs":{"type":"array","items":{"type":"string","format":"binary"},"description":"Optional product specification files (documents, images, audio, video, code). Max 50 files, 10MB total."},"productName":{"type":"string","nullable":true,"description":"The name of the product.","example":"Mobile Sales Assistant"},"userDescription":{"type":"string","minLength":1,"description":"A brief description of what the product does.","example":"A mobile sales assistant for smartphones."},"useDetailedGeneration":{"type":"string","description":"Whether to use detailed generation mode (heavier model).","example":"true"}},"required":["userDescription"]},"GenerateProductConfigResponse":{"type":"object","properties":{"name":{"type":"string","description":"The AI-refined product name."},"description":{"type":"string","description":"The AI-refined product description."},"specifications":{"type":"array","items":{"$ref":"#/components/schemas/SpecConfigResponse"},"description":"The generated testable specifications."}},"required":["name","description","specifications"]},"RegenerateProductConfigBody":{"type":"object","properties":{"productSpecs":{"type":"array","items":{"type":"string","format":"binary"},"description":"Document(s) to cross-check against the product (max 50 files, 10MB total)."},"useDetailedGeneration":{"type":"string","description":"Whether to use detailed generation mode (heavier model).","example":"true"}}},"ReplayCandidateCount":{"type":"object","properties":{"productId":{"type":"string","description":"The requested product"},"count":{"type":"integer","description":"Eligible (version, metric) replay candidates for this product"}},"required":["productId","count"]},"CreateCommentRequest":{"type":"object","properties":{"inferenceResultId":{"type":"string","description":"Inference result the comment annotates","example":"inferenceResult_123"},"text":{"type":"string","minLength":1,"maxLength":10000,"description":"Free-form annotation text","example":"Agent hallucinated the price."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":50},"maxItems":10,"description":"Reusable labels categorizing the problem this comment describes. Stored lowercase and trimmed.","example":["hallucination","tone"]}},"required":["inferenceResultId","text"]}}},"security":[{"bearerAuth":[]}],"paths":{"/health":{"get":{"summary":"Health check","description":"Health check endpoint to verify API is running. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"healthCheck","x-cli-name":"health","security":[],"responses":{"200":{"description":"API is running","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"message":{"type":"string","example":"API is running"},"timestamp":{"type":"string","format":"date-time"}}}}}}}}},"/auth/apiTokens":{"get":{"tags":["api-tokens"],"summary":"List API tokens","description":"List the authenticated user's API tokens. Secrets are never returned — only id, name, keyId and creation date.","operationId":"listApiTokens","x-cli-name":"list","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"API tokens listed successfully","content":{"application/json":{"schema":{"type":"object","required":["apiTokens"],"properties":{"apiTokens":{"type":"array","items":{"$ref":"#/components/schemas/ApiToken"}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["api-tokens"],"summary":"Create API token","description":"Create a new named API token for the authenticated user. The key is returned only once and cannot be retrieved later. Creating more than one token requires an Enterprise plan.","operationId":"createApiToken","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Optional token name. Defaults to \"default\".","example":"ci-pipeline"}}}}}},"responses":{"201":{"description":"API token created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiTokenWithSecret"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not allow creating more API tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/apiTokens/{apiTokenId}":{"patch":{"tags":["api-tokens"],"summary":"Rename API token","description":"Rename one of the authenticated user's API tokens. Always allowed, regardless of plan.","operationId":"renameApiToken","x-cli-name":"rename","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"apiTokenId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","example":"production-key"}}}}}},"responses":{"200":{"description":"API token renamed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiToken"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token does not belong to the authenticated user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"API token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["api-tokens"],"summary":"Revoke API token","description":"Revoke (permanently delete) one of the authenticated user's API tokens. Always allowed, regardless of plan.","operationId":"revokeApiToken","x-cli-name":"revoke","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"apiTokenId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"API token revoked successfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"API token revoked successfully"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token does not belong to the authenticated user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"API token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/apiTokens/{apiTokenId}/regenerate":{"post":{"tags":["api-tokens"],"summary":"Regenerate API token","description":"Rotate the secret of one of the authenticated user's API tokens. The old key stops working and the new key is returned only once. Always allowed, regardless of plan.","operationId":"regenerateApiToken","x-cli-name":"regenerate","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"apiTokenId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"API token regenerated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiTokenWithSecret"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token does not belong to the authenticated user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"API token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/user":{"get":{"tags":["auth"],"summary":"Get current user","description":"Get the currently authenticated user. See [Registration & Authentication](https://docs.galtea.ai/registration).","operationId":"getCurrentUser","x-cli-name":"get-current-user","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/organizations":{"get":{"tags":["organizations"],"summary":"Get organizations","description":"Get list of organizations with pagination and filtering. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"getOrganizations","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by organization IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by organization name","required":false,"schema":{"type":"string"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Organizations retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Organization"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/organizations/{id}":{"get":{"tags":["organizations"],"summary":"Get organization by ID","description":"Get a specific organization by ID. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"getOrganizationById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Organization ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Organization retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Organization not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/organizations/{id}/creditStatus":{"get":{"tags":["organizations"],"summary":"Get credit status","description":"Returns the current credit status for the organization, used for the credit warning badge. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"getOrganizationCreditStatus","x-cli-name":"get-credit-status","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Organization ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Credit status retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"totalCredits":{"type":"number"},"usedCredits":{"type":"number"},"remainingCredits":{"type":"number"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Organization not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/userGroups":{"get":{"tags":["user-groups"],"summary":"Get user groups","description":"Get list of user groups with pagination and filtering. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"getUserGroups","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by user group IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"organizationIds","in":"query","style":"form","explode":true,"description":"Filter by organization IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"types","in":"query","style":"form","explode":true,"description":"Filter by user group types","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"userIds","in":"query","style":"form","explode":true,"description":"Filter by user IDs (groups containing these users)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"metricIds","in":"query","style":"form","explode":true,"description":"Filter by metric IDs (groups linked to these metrics)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by user group names","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"fromCreatedAt","in":"query","description":"Filter groups created at or after this timestamp (ISO 8601)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter groups created at or before this timestamp (ISO 8601)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"User groups retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserGroup"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["user-groups"],"summary":"Create user group","description":"Create a new user group. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"createUserGroup","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","organizationId"],"properties":{"name":{"type":"string","example":"Example Name"},"organizationId":{"type":"string","example":"org_123"},"type":{"type":"string"},"description":{"type":"string","example":"A description"}}}}}},"responses":{"201":{"description":"User group created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserGroup"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/userGroups/{id}":{"get":{"tags":["user-groups"],"summary":"Get user group by ID","description":"Get a specific user group by ID. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"getUserGroupById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"User group ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User group retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserGroup"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["user-groups"],"summary":"Update user group","description":"Update an existing user group. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"updateUserGroup","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"User group ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"example":"Example Name","type":"string"}}}}}},"responses":{"200":{"description":"User group updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserGroup"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["user-groups"],"summary":"Delete user group","description":"Soft delete a user group. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"deleteUserGroup","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"User group ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"User group deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/userGroups/{id}/users":{"post":{"tags":["user-groups"],"summary":"Link users to user group","description":"Add users to a user group. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"linkUsersToUserGroup","x-cli-name":"link-users","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"User group ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userIds"],"properties":{"userIds":{"type":"array","example":["user_123","user_456"],"items":{"type":"string"}}}}}}},"responses":{"204":{"description":"Users linked successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["user-groups"],"summary":"Unlink users from user group","description":"Remove users from a user group. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"unlinkUsersFromUserGroup","x-cli-name":"unlink-users","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"User group ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userIds"],"properties":{"userIds":{"type":"array","example":["user_123","user_456"],"items":{"type":"string"}}}}}}},"responses":{"204":{"description":"Users unlinked successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/userGroups/{id}/metrics":{"post":{"tags":["user-groups"],"summary":"Link metrics to user group","description":"Add metrics to a user group. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"linkMetricsToUserGroup","x-cli-name":"link-metrics","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"User group ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metricIds"],"properties":{"metricIds":{"type":"array","example":["metric_123","metric_456"],"items":{"type":"string"}}}}}}},"responses":{"204":{"description":"Metrics linked successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["user-groups"],"summary":"Unlink metrics from user group","description":"Remove metrics from a user group. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"unlinkMetricsFromUserGroup","x-cli-name":"unlink-metrics","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"User group ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metricIds"],"properties":{"metricIds":{"type":"array","example":["metric_123","metric_456"],"items":{"type":"string"}}}}}}},"responses":{"204":{"description":"Metrics unlinked successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User group not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/userGroups/batch":{"delete":{"tags":["user-groups"],"summary":"Delete multiple user groups","description":"Soft delete multiple user groups by their IDs. See [User Groups](https://docs.galtea.ai/concepts/user-group).","operationId":"deleteUserGroups","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of user group IDs to delete"}}}}}},"responses":{"204":{"description":"User groups deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/metrics":{"get":{"tags":["metrics"],"summary":"Get metrics","description":"Get list of metrics with pagination and filtering. See [Metrics](https://docs.galtea.ai/concepts/metric).","operationId":"getMetrics","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by metric IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"organizationIds","in":"query","style":"form","explode":true,"description":"Filter by organization IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by metric names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by metric name (partial match)","required":false,"schema":{"type":"string"}},{"name":"description","in":"query","description":"Filter by metric description (partial match)","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","style":"form","explode":true,"description":"Filter by tags","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"sources","in":"query","style":"form","explode":true,"description":"Filter by metric sources","required":false,"schema":{"type":"array","items":{"type":"string","enum":["SELF_HOSTED","FULL_PROMPT","PARTIAL_PROMPT","HUMAN_EVALUATION","GEVAL","DEEPEVAL","DETERMINISTIC"]}}},{"name":"specificationIds","in":"query","style":"form","explode":true,"description":"Filter by specification IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"userGroupIds","in":"query","style":"form","explode":true,"description":"Filter by user group IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"fromCreatedAt","in":"query","description":"Filter metrics created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter metrics created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"includeDefaultEntities","in":"query","description":"Include default/predefined metrics","required":false,"schema":{"type":"boolean"}},{"name":"includeOwnEntities","in":"query","description":"Include metrics owned by the user's organization","required":false,"schema":{"type":"boolean"}},{"name":"includeLegacy","in":"query","description":"Include legacy/deprecated metrics","required":false,"schema":{"type":"boolean"}},{"name":"suitableForMonitoring","in":"query","description":"Filter metrics suitable for monitoring","required":false,"schema":{"type":"boolean"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Metrics retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Metric"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["metrics"],"summary":"Create metric","description":"Create a new metric. See [Metrics](https://docs.galtea.ai/concepts/metric).\n\nAccepted values for `source` on new metrics are `SELF_HOSTED`, `PARTIAL_PROMPT`, and `HUMAN_EVALUATION`.\n`FULL_PROMPT` is **deprecated for creation** — requests with `source=FULL_PROMPT` (or that omit\n`source` and supply a `judgePrompt` without `evaluationParams`, which previously inferred FULL_PROMPT)\nare rejected with 400. Use `PARTIAL_PROMPT` instead — it offers the same capabilities with\nuser-configurable evaluation parameters. Existing FULL_PROMPT metrics continue to be listed,\nread, filtered, and evaluated.\n","operationId":"createMetric","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Metric"}}}},"responses":{"201":{"description":"Metric created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Metric"}}}},"400":{"description":"Invalid request body (for example, `source=FULL_PROMPT` is no longer accepted)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/metrics/{id}":{"get":{"tags":["metrics"],"summary":"Get metric by ID","description":"Get a specific metric by ID. See [Metrics](https://docs.galtea.ai/concepts/metric).","operationId":"getMetricById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Metric ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metric retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Metric"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Metric not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["metrics"],"summary":"Update metric","description":"Update an existing metric. See [Metrics](https://docs.galtea.ai/concepts/metric).\n\nTo attach an existing metric to a specification (or detach it), use\n`specifications link-metrics` / `specifications unlink-metrics` — the metric-specification\nlink is managed from the specification side, not by updating the metric.\n","operationId":"updateMetric","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Metric ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Metric"}}}},"responses":{"200":{"description":"Metric updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Metric"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Metric not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["metrics"],"summary":"Delete metric","description":"Soft delete a metric. See [Metrics](https://docs.galtea.ai/concepts/metric).","operationId":"deleteMetric","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Metric ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Metric deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Metric not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/metrics/batch":{"delete":{"tags":["metrics"],"summary":"Delete multiple metrics","description":"Soft delete multiple metrics by their IDs. See [Metrics](https://docs.galtea.ai/concepts/metric).","operationId":"deleteMetrics","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of metric IDs to delete"}}}}}},"responses":{"204":{"description":"Metrics deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["metrics"],"summary":"Create multiple metrics","description":"Create multiple metrics at once. See [Metrics](https://docs.galtea.ai/concepts/metric).\n\nEach item is validated through the same path as `POST /metrics`. In particular,\n`source=FULL_PROMPT` (explicit or inferred from a `judgePrompt` without\n`evaluationParams`) is rejected with 400 — use `PARTIAL_PROMPT` instead.\n","operationId":"batchCreateMetrics","x-cli-name":"create-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metrics"],"properties":{"metrics":{"type":"array","items":{"$ref":"#/components/schemas/Metric"}}}}}}},"responses":{"201":{"description":"Metrics created successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Metric"}}}}},"400":{"description":"Invalid request body (for example, any item with `source=FULL_PROMPT` is no longer accepted)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/metrics/{id}/replay-candidate-count":{"get":{"tags":["metrics"],"summary":"Count replay candidates per product for a metric revision","description":"For each requested product, returns how many historical evaluations in this metric's group would be replayed against this revision. Any `(sessionId, inferenceResultId)` pair already evaluated with this metric is excluded. Products with no candidates return `count: 0`.\n","operationId":"getReplayCandidateCount","x-cli-name":"get-replay-candidate-count","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Metric revision ID","required":true,"schema":{"type":"string"}},{"name":"productIds","in":"query","style":"form","explode":true,"required":true,"description":"Repeated query param; one value per product.","schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"Candidate counts per product","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"productId":{"type":"string"},"count":{"type":"integer"}}}}}}},"400":{"description":"Invalid query","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Metric or product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/metrics/{id}/human-annotation-count":{"get":{"tags":["metrics"],"summary":"Get human annotation count and optimization eligibility","description":"Returns the optimization-eligibility snapshot for a metric.\n\n`count` is the number of evaluations that have both an AI score and a\nhuman-provided score (annotation). For FULL_PROMPT/PARTIAL_PROMPT metrics\nthis means the AI judged the evaluation and a human later reviewed it.\nFor HUMAN_EVALUATION metrics both fields hold the same human-provided\nvalue (for analytics compatibility).\n\n`disagreementCount` is the subset of `count` where the human verdict flips\nthe AI's verdict — both are binarized at 0.5 (any score >= 0.5 is class 1,\nanything below is class 0) and the row counts only when the two classes\ndiffer. These are the rows the optimizer learns from.\n\n`minAnnotations` and `minDisagreements` are the api-enforced thresholds\n(mirrored from the metrics-generator hard thresholds). Optimize is rejected\nearly unless `count >= minAnnotations` AND `disagreementCount >= minDisagreements`.\n","operationId":"getMetricHumanAnnotationCount","x-cli-name":"get-annotation-count","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Metric ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Annotation/disagreement counts and thresholds retrieved successfully","content":{"application/json":{"schema":{"type":"object","required":["count","disagreementCount","minAnnotations","minDisagreements"],"properties":{"count":{"type":"integer","description":"Evaluations with both an AI score and a human score."},"disagreementCount":{"type":"integer","description":"Subset of `count` where the human verdict flips the AI's (AI and human on opposite sides of 0.5)."},"minAnnotations":{"type":"integer","description":"Minimum annotations required to optimize this metric."},"minDisagreements":{"type":"integer","description":"Minimum disagreements required to optimize this metric."}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Metric not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/metrics/{id}/optimize":{"post":{"tags":["metrics"],"summary":"Optimize metric","description":"Creates an optimized copy of a metric by sending its human-annotated evaluations to the metrics-generator service, which uses the gap between AI and human scores to produce a better judge prompt. Only FULL_PROMPT and PARTIAL_PROMPT metrics owned by an organization can be optimized. Rejected with 400 unless the metric has at least `minAnnotations` evaluations annotated by a human AND `minDisagreements` of those disagree with the AI score; both thresholds are returned by `GET /metrics/{id}/human-annotation-count` (defaults `10` and `5`, configurable via the `OPTIMIZE_MIN_ANNOTATIONS_HARD` / `OPTIMIZE_MIN_DISAGREEMENTS_HARD` env vars). 30+ annotations recommended for best optimizer signal. Returns a placeholder metric with isBeingOptimized=true. See [Metrics](https://docs.galtea.ai/concepts/metric).","operationId":"optimizeMetric","x-cli-name":"optimize","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Source Metric ID","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Optimized metric placeholder created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Metric"}}}},"400":{"description":"Metric is not eligible for optimization (wrong source, no organizationId, fewer than `minAnnotations` annotated evaluations, or fewer than `minDisagreements` annotations where the human verdict flips the AI's — both binarized at 0.5). Read both thresholds and the current counts from `GET /metrics/{id}/human-annotation-count`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Metric not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/metrics/generate-config":{"post":{"tags":["metrics"],"summary":"Generate or complete metric configuration with AI","description":"Two modes, selected by the request body:\n\n- **Spec mode** (provide `specificationIds`): generates 1-3 metric configurations per\n  specification, optionally creating the metrics automatically.\n- **Completion mode** (\"Complete With AI\", provide `name` + `description` + `evaluationType`):\n  completes a single metric the user is authoring. The name/description/evaluationType/tags\n  are the source of truth; only the judge prompt, evaluation params, and evaluator model are\n  generated. `specificationIds` may carry at most one id as optional context.\n\nSee [Metrics](https://docs.galtea.ai/concepts/metric).\n","operationId":"generateMetricConfig","x-cli-name":"generate-config","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"specificationIds":{"type":"array","example":["spec_123","spec_456"],"items":{"type":"string"},"description":"Spec mode - IDs of the specifications to generate metrics for. Completion mode - at most one id used as context."},"automaticCreation":{"type":"boolean","description":"Spec mode only - when true, creates metrics from generated config","example":false},"maxMetricsPerSpecification":{"type":"integer","description":"Spec mode only - maximum number of metrics to generate per specification"},"isOnboarding":{"type":"boolean","description":"Spec mode only - whether this is an onboarding flow","example":false},"name":{"type":"string","description":"Completion mode - the user-authored metric name (source of truth)"},"description":{"type":"string","description":"Completion mode - the user-authored metric description (the criteria to evaluate)"},"evaluationType":{"type":"string","enum":["PARTIAL_PROMPT","HUMAN_EVALUATION"],"description":"Completion mode - PARTIAL_PROMPT (binary LLM judge) or HUMAN_EVALUATION (0-100 annotator guidelines)"},"tags":{"type":"array","items":{"type":"string"},"description":"Completion mode - user-provided tags (source of truth, optional)"},"productId":{"type":"string","description":"Completion mode - optional product id for additional context"}}}}}},"responses":{"200":{"description":"Metric configuration generated successfully","content":{"application/json":{"schema":{"type":"object","description":"Generated metric configuration suggestion"}}}},"201":{"description":"Metrics created from generated configuration","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Metric"}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/specifications":{"get":{"tags":["specifications"],"summary":"Get specifications","description":"Get list of specifications with pagination and filtering. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"getSpecifications","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by specification IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"organizationIds","in":"query","style":"form","explode":true,"description":"Filter by organization IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"types","in":"query","style":"form","explode":true,"description":"Filter by specification types (CAPABILITY, INABILITY, POLICY)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"testTypes","in":"query","style":"form","explode":true,"description":"Filter by test types","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"metricIds","in":"query","style":"form","explode":true,"description":"Filter by linked metric IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by specification name (partial match)","required":false,"schema":{"type":"string"}},{"name":"description","in":"query","description":"Filter by specification description (partial match)","required":false,"schema":{"type":"string"}},{"name":"fromCreatedAt","in":"query","description":"Filter by creation date (from)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter by creation date (to)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Specifications retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Specification"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["specifications"],"summary":"Create specification","description":"Create a new specification. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"createSpecification","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Specification"}}}},"responses":{"201":{"description":"Specification created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Specification"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/specifications/{id}":{"get":{"tags":["specifications"],"summary":"Get specification by ID","description":"Get a specific specification by ID. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"getSpecificationById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Specification ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Specification retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Specification"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Specification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["specifications"],"summary":"Update specification","description":"Update an existing specification. See [Specifications](https://docs.galtea.ai/concepts/product/specification).\n\nLinked tests and metrics are **not** edited through this endpoint. To manage links use\n`specifications link-tests` / `specifications unlink-tests` and\n`specifications link-metrics` / `specifications unlink-metrics`\n(with `specifications list-tests` / `specifications list-metrics` to inspect what is currently linked).\n","operationId":"updateSpecification","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Specification ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Specification"}}}},"responses":{"200":{"description":"Specification updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Specification"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Specification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteSpecification","tags":["specifications"],"summary":"Delete specification","description":"Soft delete a specification. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","security":[{"bearerAuth":[]}],"x-cli-name":"delete","parameters":[{"schema":{"type":"string","description":"Specification ID","example":"spec_123"},"required":true,"description":"Specification ID","name":"id","in":"path"}],"responses":{"204":{"description":"Specification deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/specifications/batch":{"post":{"tags":["specifications"],"summary":"Create multiple specifications","description":"Create multiple specifications at once. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"batchCreateSpecifications","x-cli-name":"create-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["specifications"],"properties":{"specifications":{"type":"array","items":{"$ref":"#/components/schemas/Specification"}}}}}}},"responses":{"201":{"description":"Specifications created successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Specification"}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["specifications"],"summary":"Delete multiple specifications","description":"Soft delete multiple specifications by their IDs. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"deleteSpecifications","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of specification IDs to delete"}}}}}},"responses":{"204":{"description":"Specifications deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/specifications/{id}/metrics":{"post":{"tags":["specifications"],"summary":"Link metrics to specification","description":"Link one or more metrics to a specification. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"linkMetricsToSpecification","x-cli-name":"link-metrics","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Specification ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metricIds"],"properties":{"metricIds":{"type":"array","example":["metric_123","metric_456"],"items":{"type":"string"},"description":"Array of metric IDs to link"}}}}}},"responses":{"204":{"description":"Metrics linked successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Specification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["specifications"],"summary":"Unlink metrics from specification","description":"Unlink one or more metrics from a specification. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"unlinkMetricsFromSpecification","x-cli-name":"unlink-metrics","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Specification ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metricIds"],"properties":{"metricIds":{"type":"array","example":["metric_123","metric_456"],"items":{"type":"string"},"description":"Array of metric IDs to unlink"}}}}}},"responses":{"204":{"description":"Metrics unlinked successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Specification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["specifications"],"summary":"Get linked metrics","description":"Get all metrics linked to a specification. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"getSpecificationMetrics","x-cli-name":"list-metrics","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Specification ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Metric"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Specification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/specifications/{id}/tests":{"post":{"tags":["specifications"],"summary":"Link tests to specification","description":"Link one or more tests to a specification. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"linkTestsToSpecification","x-cli-name":"link-tests","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Specification ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["testIds"],"properties":{"testIds":{"type":"array","items":{"type":"string"},"description":"Array of test IDs to link"}}}}}},"responses":{"204":{"description":"Tests linked successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"},"404":{"description":"Specification not found"}}},"delete":{"tags":["specifications"],"summary":"Unlink tests from specification","description":"Unlink one or more tests from a specification. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"unlinkTestsFromSpecification","x-cli-name":"unlink-tests","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Specification ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["testIds"],"properties":{"testIds":{"type":"array","items":{"type":"string"},"description":"Array of test IDs to unlink"}}}}}},"responses":{"204":{"description":"Tests unlinked successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"},"404":{"description":"Specification not found"}}},"get":{"tags":["specifications"],"summary":"Get linked tests","description":"Get all tests linked to a specification. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","operationId":"getSpecificationTests","x-cli-name":"list-tests","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Specification ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tests retrieved successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Specification not found"}}}},"/models":{"get":{"tags":["models"],"summary":"Get models","description":"Get list of models with pagination and filtering. See [Models](https://docs.galtea.ai/concepts/model).","operationId":"getModels","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by model IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"organizationIds","in":"query","style":"form","explode":true,"description":"Filter by organization IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by model names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by model name (partial match)","required":false,"schema":{"type":"string"}},{"name":"includeDefaultEntities","in":"query","description":"Include default/predefined models","required":false,"schema":{"type":"boolean"}},{"name":"includeOwnEntities","in":"query","description":"Include models owned by the user's organization","required":false,"schema":{"type":"boolean"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter models created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter models created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Models retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Model"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["models"],"summary":"Create model","description":"Create a new model. See [Models](https://docs.galtea.ai/concepts/model).","operationId":"createModel","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"responses":{"201":{"description":"Model created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/models/{id}":{"get":{"tags":["models"],"summary":"Get model by ID","description":"Get a specific model by ID. See [Models](https://docs.galtea.ai/concepts/model).","operationId":"getModelById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Model ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Model retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["models"],"summary":"Update model","description":"Update an existing model. See [Models](https://docs.galtea.ai/concepts/model).","operationId":"updateModel","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Model ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"responses":{"200":{"description":"Model updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["models"],"summary":"Delete model","description":"Soft delete a model. See [Models](https://docs.galtea.ai/concepts/model).","operationId":"deleteModel","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Model ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Model deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/models/batch":{"delete":{"tags":["models"],"summary":"Delete multiple models","description":"Soft delete multiple models by their IDs. See [Models](https://docs.galtea.ai/concepts/model).","operationId":"deleteModels","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of model IDs to delete"}}}}}},"responses":{"204":{"description":"Models deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products":{"get":{"tags":["products"],"summary":"Get products","description":"Get list of products with pagination and filtering options. See [Products](https://docs.galtea.ai/concepts/product).","operationId":"getProducts","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"organizationIds","in":"query","style":"form","explode":true,"description":"Filter by organization IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by product names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by product name (partial match)","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","style":"form","explode":true,"description":"Filter by tags (returns products with at least one matching tag)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"cloned","in":"query","description":"Filter by product origin: `true` returns demo/cloned products (source is not null), `false` returns user-created products (source is null). Combine with limit=0 to read only the matching count from the Content-Range header.","required":false,"schema":{"type":"boolean"}},{"name":"fromCreatedAt","in":"query","description":"Filter products created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter products created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort parameters","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results to return","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Products retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Product"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["products"],"summary":"Create product","description":"Create a new product. See [Products](https://docs.galtea.ai/concepts/product).","operationId":"createProduct","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"description":"Product data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"responses":{"201":{"description":"Product created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/tags":{"get":{"tags":["products"],"summary":"List distinct product tags","description":"Returns the sorted, distinct set of tags used across products in the requested\norganizations. Tags are returned lowercase and trimmed. Powers tag-suggestion\nUIs in the dashboard and the product-list tag filter.\n\nOrg scope resolves like every list endpoint (ADR 0029): with no `organizationIds`, the\ncaller's own organization is used by default (admins reach all orgs via `allOrganizations`).\nA non-admin requesting tags for an organization they cannot read receives 403.\n","operationId":"listProductTags","x-cli-name":"list-tags","security":[{"bearerAuth":[]}],"parameters":[{"name":"organizationIds","in":"query","style":"form","explode":true,"description":"Filter by organization IDs. Optional — defaults to the caller's own organization.","required":false,"schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"Tags retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"example":["beta","internal"]}}}},"400":{"description":"Missing tenant-scoping filter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"No permission to view tags for the requested organizations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/{id}":{"get":{"tags":["products"],"summary":"Get product by ID","description":"Get a specific product by ID. See [Products](https://docs.galtea.ai/concepts/product).","operationId":"getProductById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Product ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Product retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["products"],"summary":"Update product","description":"Update an existing product. See [Products](https://docs.galtea.ai/concepts/product).","operationId":"updateProduct","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Product ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"description":"Updated product data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"responses":{"200":{"description":"Product updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["products"],"summary":"Delete product","description":"Soft delete a product. See [Products](https://docs.galtea.ai/concepts/product).","operationId":"deleteProduct","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Product ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Product deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/batch":{"delete":{"tags":["products"],"summary":"Delete multiple products","description":"Soft delete multiple products by their IDs. See [Products](https://docs.galtea.ai/concepts/product).","operationId":"deleteProducts","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of product IDs to delete"}}}}}},"responses":{"204":{"description":"Products deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/versions":{"get":{"tags":["versions"],"summary":"Get versions","description":"Get list of versions with pagination and filtering options. See [Versions](https://docs.galtea.ai/concepts/product/version).","operationId":"getVersions","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by version IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"modelIds","in":"query","style":"form","explode":true,"description":"Filter by model IDs (the model assigned to the version)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"parentVersionIds","in":"query","style":"form","explode":true,"description":"Filter by parent version IDs. Returns the revisions whose parent is one of these versions (the versions revised from them).","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"conversationEndpointConnectionIds","in":"query","style":"form","explode":true,"description":"Filter by conversation endpoint connection IDs (include only). Use an empty string (\"\") to select versions without a conversation endpoint connection","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"excludeConversationEndpointConnectionIds","in":"query","style":"form","explode":true,"description":"Omit versions with the specified conversation endpoint connection IDs. Use an empty string (\"\") to omit versions without a conversation endpoint connection","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"phoneConnectionIds","in":"query","style":"form","explode":true,"description":"Filter by phone connection IDs (include only). Use an empty string (\"\") to select versions without a phone connection","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"excludePhoneConnectionIds","in":"query","style":"form","explode":true,"description":"Omit versions with the specified phone connection IDs. Use an empty string (\"\") to omit versions without a phone connection","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"webRtcConnectionIds","in":"query","style":"form","explode":true,"description":"Filter by WebRTC connection IDs (include only). Use an empty string (\"\") to select versions without a WebRTC connection","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"excludeWebRtcConnectionIds","in":"query","style":"form","explode":true,"description":"Omit versions with the specified WebRTC connection IDs. Use an empty string (\"\") to omit versions without a WebRTC connection","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by version names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by version name (partial match)","required":false,"schema":{"type":"string"}},{"name":"existentInEvaluations","in":"query","description":"Filter versions that have evaluations","required":false,"schema":{"type":"boolean"}},{"name":"hasInferenceResults","in":"query","description":"Filter versions that have inference results","required":false,"schema":{"type":"boolean"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter versions created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter versions created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Versions retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Version"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["versions"],"summary":"Create version","description":"Create a new version. See [Versions](https://docs.galtea.ai/concepts/product/version).","operationId":"createVersion","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Version"}}}},"responses":{"201":{"description":"Version created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Version"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/versions/{id}":{"get":{"tags":["versions"],"summary":"Get version by ID","description":"Get a specific version by ID. See [Versions](https://docs.galtea.ai/concepts/product/version).","operationId":"getVersionById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Version ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Version retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Version"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Version not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["versions"],"summary":"Update version","description":"Update an existing version. See [Versions](https://docs.galtea.ai/concepts/product/version).","operationId":"updateVersion","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Version ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Version"}}}},"responses":{"200":{"description":"Version updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Version"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Version not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["versions"],"summary":"Delete version","description":"Soft delete a version. See [Versions](https://docs.galtea.ai/concepts/product/version).","operationId":"deleteVersion","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Version ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Version deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Version not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/versions/{id}/compatible-metrics":{"get":{"tags":["versions"],"summary":"List metrics annotated with compatibility for a version","description":"Returns evaluable metrics annotated with whether they can be satisfied by the version's product metadata and conversation endpoint connection output mapping, plus a `relevance` ranking against the tests the evaluation will run against. Trace-dependent and runtime-only params are out of scope and treated as always satisfied. When `testIds` are supplied, each metric is ranked `linked` (linked to a specification of one of those tests), `matching` (linked to a same-product specification whose testType matches one of those tests), or `none`. Without `testIds` every metric is `none`.","operationId":"listCompatibleMetricsByVersion","x-cli-name":"list-compatible-metrics","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Version ID to evaluate compatibility against","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of metrics to return (default 100)","required":false,"schema":{"type":"integer"}},{"name":"testIds","in":"query","style":"form","explode":true,"description":"Tests the evaluation will run against; drives the `relevance` ranking. All tests must belong to the version's product.","required":false,"schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"List of metrics with compatibility and relevance annotations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CompatibleMetric"}}}}},"400":{"description":"A supplied testId does not belong to the version's product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Version not found, or a supplied testId does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/versions/batch":{"delete":{"tags":["versions"],"summary":"Delete multiple versions","description":"Soft delete multiple versions by their IDs. See [Versions](https://docs.galtea.ai/concepts/product/version).","operationId":"deleteVersions","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of version IDs to delete"}}}}}},"responses":{"204":{"description":"Versions deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/monitors":{"get":{"tags":["monitors"],"summary":"Get monitors","description":"Get list of monitors with pagination and filtering. See [Monitors](https://docs.galtea.ai/concepts/product/monitor).","operationId":"getMonitors","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by monitor IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"versionIds","in":"query","style":"form","explode":true,"description":"Filter by version IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by monitor names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by monitor name (partial match)","required":false,"schema":{"type":"string"}},{"name":"statuses","in":"query","style":"form","explode":true,"description":"Filter by monitor statuses","required":false,"schema":{"type":"array","items":{"type":"string","enum":["ACTIVE","PAUSED","CAPPED","NO_CREDITS","FAILING"]}}},{"name":"metricGroupIds","in":"query","style":"form","explode":true,"description":"Filter by bound metric family IDs (Metric.metricGroupId)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter monitors created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter monitors created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Monitors retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Monitor"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["monitors"],"summary":"Create monitor","description":"Create a new monitor. See [Monitors](https://docs.galtea.ai/concepts/product/monitor).","operationId":"createMonitor","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Monitor"}}}},"responses":{"201":{"description":"Monitor created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Monitor"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/monitors/{id}":{"get":{"tags":["monitors"],"summary":"Get monitor by ID","description":"Get a specific monitor by ID. See [Monitors](https://docs.galtea.ai/concepts/product/monitor).","operationId":"getMonitorById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Monitor retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Monitor"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Monitor not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["monitors"],"summary":"Update monitor","description":"Update an existing monitor. Pause or resume a monitor by setting status to PAUSED or ACTIVE. See [Monitors](https://docs.galtea.ai/concepts/product/monitor).","operationId":"updateMonitor","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Monitor"}}}},"responses":{"200":{"description":"Monitor updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Monitor"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Monitor not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["monitors"],"summary":"Delete monitor","description":"Soft delete a monitor. See [Monitors](https://docs.galtea.ai/concepts/product/monitor).","operationId":"deleteMonitor","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Monitor deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Monitor not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/monitors/{id}/results":{"get":{"tags":["monitors"],"summary":"Get monitor results","description":"Aggregated results for a monitor over a trailing window (default 7 days, bucketed by day): per-metric-family sampling-weighted score series with 95% confidence intervals, the worst metric family, metric-revision and sampling-change markers, current-cycle credit spend, and the scored/waiting session listing. Below 30 scored sessions a bucket reports a collecting-data state instead of an interval. Computed only from the monitor's own evaluations.\n","operationId":"getMonitorResults","x-cli-name":"get-results","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","description":"Trailing window in days to aggregate (default 7, max 90).","required":false,"schema":{"type":"integer","minimum":1,"maximum":90}}],"responses":{"200":{"description":"Monitor results retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResults"}}}},"400":{"description":"Invalid query parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The monitor belongs to another organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Monitor not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/monitors/preview":{"post":{"tags":["monitors"],"summary":"Preview monitor content-filter matches","description":"Read-only preview for a CANDIDATE monitor config: how many and which recent past sessions the given content filter and sampling percentage would select, over a trailing window. Runs no evaluations, spends no credits, and writes nothing (no processed marks). Use it while creating or editing a monitor. The match count is exact; for a create preview (no `monitorId`) the sampled subset is representative, not the exact set the created monitor will draw.\n","operationId":"previewMonitorMatches","x-cli-name":"preview","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productId","samplingPercentage"],"properties":{"productId":{"type":"string","description":"Product whose recent production sessions the preview scans.","example":"prod_123"},"versionId":{"type":"string","nullable":true,"description":"Optional version to narrow the preview to. Null previews the whole product.","example":"version_123"},"filterQuery":{"type":"string","nullable":true,"maxLength":500,"description":"Candidate content filter. Null means every recent session matches (sampling only).","example":"refund"},"filterTarget":{"type":"string","enum":["INPUT","OUTPUT","EITHER"],"nullable":true,"description":"Which side of a turn filterQuery matches against. Set together with filterQuery.","example":"EITHER"},"excludeQuery":{"type":"string","nullable":true,"maxLength":500,"description":"Candidate exclude filter. Comma-separated terms; a session is dropped when a turn whose chosen target (excludeTarget) contains ANY term. Null excludes nothing. Set together with excludeTarget. Independent of filterQuery.\n","example":"test, internal"},"excludeTarget":{"type":"string","enum":["INPUT","OUTPUT","EITHER"],"nullable":true,"description":"Which side of a turn excludeQuery matches against. Set together with excludeQuery.","example":"EITHER"},"samplingPercentage":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":100,"description":"Candidate sampling percentage (greater than 0, at most 100).","example":10},"days":{"type":"integer","minimum":1,"maximum":90,"description":"Trailing window in days to look back over (default 90, max 90).","example":90},"monitorId":{"type":"string","nullable":true,"description":"Existing monitor id when previewing an EDIT, so sampling uses its real seed (exact). Omit for a create preview (representative sampling).\n","example":"monitor_123"}}}}}},"responses":{"200":{"description":"Preview computed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorMatchPreview"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The caller cannot create monitors for this product. A product in another organization also yields 403 (not 404), so the endpoint never leaks whether a foreign product exists.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No product exists with the given id (a product in another organization yields 403, not 404)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/monitors/batch":{"delete":{"tags":["monitors"],"summary":"Delete multiple monitors","description":"Soft delete multiple monitors by their IDs. See [Monitors](https://docs.galtea.ai/concepts/product/monitor).","operationId":"deleteMonitors","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of monitor IDs to delete"}}}}}},"responses":{"204":{"description":"Monitors deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/endpointConnections":{"get":{"tags":["endpoint-connections"],"summary":"Get endpoint connections","description":"Get list of endpoint connections with pagination and filtering. See [Endpoint Connections](https://docs.galtea.ai/concepts/product/endpoint-connection).","operationId":"getEndpointConnections","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by endpoint connection IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by endpoint connection names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by endpoint connection name (partial match)","required":false,"schema":{"type":"string"}},{"name":"url","in":"query","description":"Filter by URL (partial match)","required":false,"schema":{"type":"string"}},{"name":"types","in":"query","style":"form","explode":true,"description":"Filter by endpoint connection types","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"httpMethods","in":"query","style":"form","explode":true,"description":"Filter by HTTP methods","required":false,"schema":{"type":"array","items":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]}}},{"name":"authTypes","in":"query","style":"form","explode":true,"description":"Filter by authentication types","required":false,"schema":{"type":"array","items":{"type":"string","enum":["NONE","BEARER","API_KEY","BASIC"]}}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter endpoint connections created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter endpoint connections created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Endpoint connections retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EndpointConnection"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["endpoint-connections"],"summary":"Create endpoint connection","description":"Create a new endpoint connection. See [Endpoint Connections](https://docs.galtea.ai/concepts/product/endpoint-connection).","operationId":"createEndpointConnection","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointConnection"}}}},"responses":{"201":{"description":"Endpoint connection created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointConnection"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/endpointConnections/{id}":{"get":{"tags":["endpoint-connections"],"summary":"Get endpoint connection by ID","description":"Get a specific endpoint connection by ID. See [Endpoint Connections](https://docs.galtea.ai/concepts/product/endpoint-connection).","operationId":"getEndpointConnectionById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"EndpointConnection ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Endpoint connection retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointConnection"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpoint connection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["endpoint-connections"],"summary":"Update endpoint connection","description":"Update an existing endpoint connection. See [Endpoint Connections](https://docs.galtea.ai/concepts/product/endpoint-connection).","operationId":"updateEndpointConnection","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"EndpointConnection ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointConnection"}}}},"responses":{"200":{"description":"Endpoint connection updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointConnection"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpoint connection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["endpoint-connections"],"summary":"Delete endpoint connection","description":"Soft delete an endpoint connection. See [Endpoint Connections](https://docs.galtea.ai/concepts/product/endpoint-connection).","operationId":"deleteEndpointConnection","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"EndpointConnection ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Endpoint connection deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpoint connection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/endpointConnections/testConnection":{"post":{"tags":["endpoint-connections"],"summary":"Test endpoint connection","description":"Test an endpoint connection by making a sample request. Can be used in two modes: (1) Without an ID — all connection fields are required (creation flow). (2) With an ID — fetches the stored connection and applies any provided fields as overrides (update flow). See [Endpoint Connections](https://docs.galtea.ai/concepts/product/endpoint-connection).\n","operationId":"testEndpointConnection","x-cli-name":"test","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Optional ID of an existing endpoint connection. When provided, stored connection data is used as base and remaining fields act as overrides.","example":"id_123"},"url":{"type":"string","description":"The endpoint URL to test","example":"https://api.example.com"},"httpMethod":{"type":"string","description":"HTTP method (GET, POST, etc.)"},"authType":{"type":"string","description":"Authentication type (NONE, BEARER, API_KEY, BASIC)"},"authToken":{"type":"string","description":"Authentication token (for BEARER or API_KEY)"},"username":{"type":"string","description":"Username (for BASIC auth)"},"password":{"type":"string","description":"Password (for BASIC auth)","example":"securePass123!"},"headers":{"type":"object","description":"Custom headers as key-value pairs"},"inputTemplate":{"type":"string","description":"Input template with Jinja2 placeholders"},"timeout":{"type":"number","description":"Request timeout in seconds"}}}}}},"responses":{"200":{"description":"Test connection result","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"statusCode":{"type":"number"},"latency":{"type":"number"},"response":{"type":"object"},"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpoint connection not found (when id is provided)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/endpointConnections/parse-curl":{"post":{"tags":["endpoint-connections"],"summary":"Parse a cURL command into endpoint connection fields","description":"Parse a raw cURL command into best-effort endpoint-connection fields (URL, HTTP method, headers, auth type/token, request body, and a derived input template). The parse is best-effort: a command that cannot be fully parsed still returns the partial entity together with a structured `errors` array describing what could not be parsed — nothing is discarded on partial failure. The parsed fields are NOT persisted; the caller applies them to a creation form. See [Endpoint Connections](https://docs.galtea.ai/concepts/product/endpoint-connection).\n","operationId":"parseCurlEndpointConnection","x-cli-name":"parse-curl","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["curl"],"properties":{"curl":{"type":"string","description":"The raw cURL command to parse.","example":"curl https://api.example.com/v1/chat -H 'Authorization: Bearer sk-123' -d '{\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}'"},"connectionType":{"type":"string","enum":["INITIALIZATION","CONVERSATION","FINALIZATION"],"description":"Target endpoint-connection type. Optional; defaults to CONVERSATION. CONVERSATION runs an LLM pass to enrich the derived input template; INITIALIZATION and FINALIZATION seed the input template with the raw JSON body verbatim (no placeholder, no AI).\n","example":"CONVERSATION"},"productName":{"type":"string","description":"Optional product name, used only as naming signal for the suggested connection `name` in the response. Not persisted and never referenced by the input template. When omitted the name is derived from the URL.\n","example":"Acme Support"}}}}}},"responses":{"200":{"description":"Parsed endpoint connection fields (best effort) with any structured parse errors.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseCurlEndpointConnectionResult"}}}},"400":{"description":"Missing or empty cURL command","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/endpointConnections/batch":{"delete":{"tags":["endpoint-connections"],"summary":"Delete multiple endpoint connections","description":"Soft delete multiple endpoint connections by their IDs. See [Endpoint Connections](https://docs.galtea.ai/concepts/product/endpoint-connection).","operationId":"deleteEndpointConnections","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of endpoint connection IDs to delete"}}}}}},"responses":{"204":{"description":"Endpoint connections deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tests":{"get":{"tags":["tests"],"summary":"Get tests","description":"Get list of tests with pagination and filtering options. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"getTests","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by test IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"testCaseIds","in":"query","style":"form","explode":true,"description":"Filter by test case IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"versionIds","in":"query","style":"form","explode":true,"description":"Filter by version IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by test names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by test name (partial match)","required":false,"schema":{"type":"string"}},{"name":"types","in":"query","style":"form","explode":true,"description":"Filter by test types","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"specificationIds","in":"query","style":"form","explode":true,"description":"Filter by specification IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"existentInEvaluations","in":"query","description":"Filter tests that have evaluations","required":false,"schema":{"type":"boolean"}},{"name":"hasInferenceResults","in":"query","description":"Filter tests that have inference results","required":false,"schema":{"type":"boolean"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter tests created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter tests created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Tests retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Test"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["tests"],"summary":"Create test","description":"Create a new test. See [Tests](https://docs.galtea.ai/concepts/product/test).\n\n**File uploads.** The `uri`, `groundTruthUri`, and `dataCatalogUri` fields of `TestInput`\neach expect a presigned GET URL (S3 `X-Amz-*` or Azure Blob SAS) for a file that was\nalready uploaded via the storage PUT-presign endpoint. The server strips the signing\nquery and persists the underlying storage URI (`s3://<bucket>/<key>` for S3, or the\nquery-less blob URL for Azure) on the created test.\n\nProviding `uri` switches the request into \"custom test file\" mode: generation is\nskipped, the test is created in `SUCCESS` state, and credit checks / `maxTestCases`\n/ generator-specific validations are bypassed.\n\nCreation is the only time `specificationId` can be set directly. To attach an\nexisting test to a specification afterwards, use `specifications link-tests`.\n","operationId":"createTest","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"description":"Test data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestInput"}}}},"responses":{"201":{"description":"Test created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Test"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tests/types":{"get":{"tags":["tests"],"summary":"Get test types used by the organization","description":"Retrieves the non-repeated test types of all the products of the user's organization. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"getTestTypes","x-cli-name":"list-types","security":[{"bearerAuth":[]}],"parameters":[{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"Test types retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"string"},"example":["QUALITY","RED_TEAMING","SCENARIOS"]}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tests/{id}/extend":{"post":{"tags":["tests"],"summary":"Extend a generated test with more cases","description":"Re-run the generator that originally produced this test (scenario, red teaming, or gold standard) and append the new cases to it. Only tests Galtea generated from a specification or ground-truth document can be extended. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"extendTest","x-cli-name":"extend","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"ID of the generated test to extend"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer","description":"How many extra cases to generate (defaults to 10, max 200)"}}}}}},"responses":{"202":{"description":"Extension task started"},"400":{"description":"Bad request (test cannot be extended or insufficient credits)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tests/batch":{"post":{"tags":["tests"],"summary":"Create multiple tests","description":"Create multiple tests at once. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"batchCreateTests","x-cli-name":"create-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tests"],"properties":{"tests":{"type":"array","items":{"$ref":"#/components/schemas/TestInput"}}}}}}},"responses":{"201":{"description":"Tests created successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Test"}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["tests"],"summary":"Delete multiple tests","description":"Soft delete multiple tests by their IDs. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"deleteTests","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of test IDs to delete"}}}}}},"responses":{"204":{"description":"Tests deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tests/generate-config":{"post":{"tags":["tests"],"summary":"Generate test configuration from specifications","description":"Derives test type, variant, and name from specifications (rule-based). Optionally creates tests automatically. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"generateTestConfig","x-cli-name":"generate-config","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["specificationIds"],"properties":{"specificationIds":{"type":"array","example":["spec_123","spec_456"],"items":{"type":"string"},"description":"IDs of the specifications to generate test configs for"},"automaticCreation":{"type":"boolean","description":"When true, creates tests from generated config","example":false}}}}}},"responses":{"200":{"description":"Test configuration generated successfully","content":{"application/json":{"schema":{"type":"object","description":"Generated test configuration suggestion"}}}},"201":{"description":"Tests created from generated configuration","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Test"}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tests/{id}":{"get":{"tags":["tests"],"summary":"Get test by ID","description":"Get a specific test by ID. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"getTestById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Test ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Test retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Test"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Test not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["tests"],"summary":"Update test","description":"Apply a partial update to an existing test. See [Tests](https://docs.galtea.ai/concepts/product/test).\n\n**Only `name` and `metadata` are mutable** post-creation. Attempting to update any\nother field (`type`, `variants`, `strategies`, `uri`, `groundTruthUri`,\n`dataCatalogUri`, `sourceTestId`, `maxTestCases`, etc.) returns a 400. Those are\nfixed for the lifetime of the test because they drive generation, credit accounting,\nand stored test-case shape.\n\nTo attach an existing test to a specification (or detach it), use\n`specifications link-tests` / `specifications unlink-tests` — the test-specification\nlink is managed from the specification side, not by updating the test.\n","operationId":"updateTest","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Test ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"description":"Fields to update. Only `name` and `metadata` are accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestUpdateInput"}}}},"responses":{"200":{"description":"Test updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Test"}}}},"400":{"description":"Bad request — disallowed field in payload or invalid value for `name` / `metadata`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Test not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["tests"],"summary":"Delete test","description":"Soft delete a test. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"deleteTest","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Test ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Test deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Test not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/testCases":{"get":{"tags":["test-cases"],"summary":"Get test cases","description":"Get list of test cases with pagination and filtering options. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"getTestCases","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by test case IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"testIds","in":"query","style":"form","explode":true,"description":"Filter by test IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"input","in":"query","description":"Case-insensitive substring filter applied across the test case input JSON values","required":false,"schema":{"type":"string"}},{"name":"reviewed","in":"query","description":"Filter by review status","required":false,"schema":{"type":"boolean"}},{"name":"userScore","in":"query","description":"Filter by user score","required":false,"schema":{"type":"integer"}},{"name":"variants","in":"query","style":"form","explode":true,"description":"Filter by variants","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"strategies","in":"query","style":"form","explode":true,"description":"Filter by strategies","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"languages","in":"query","style":"form","explode":true,"description":"Filter by language codes","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"sourceFiles","in":"query","style":"form","explode":true,"description":"Filter by source files","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"expectedTools","in":"query","style":"form","explode":true,"description":"Filter by expected tools","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"isAugmented","in":"query","description":"Filter by augmentation status","required":false,"schema":{"type":"boolean"}},{"name":"includeLegacy","in":"query","description":"Include superseded revisions. Defaults to true; pass false to return only the active head of each revision family (legacyAt is null).","required":false,"schema":{"type":"boolean"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter test cases created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter test cases created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Test cases retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TestCase"}}}}},"400":{"description":"Invalid request parameters (e.g. malformed sort).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["test-cases"],"summary":"Create test case","description":"Create a new test case. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"createTestCase","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestCase"}}}},"responses":{"201":{"description":"Test case created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestCase"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/testCases/languages":{"get":{"tags":["test-cases"],"summary":"Get test case languages","description":"Get all available languages for test cases. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"getTestCaseLanguages","x-cli-name":"list-languages","security":[{"bearerAuth":[]}],"parameters":[{"name":"productId","in":"query","description":"Product ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Languages retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"languages":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/testCases/export":{"post":{"tags":["test-cases"],"summary":"Export test cases as CSV","description":"Generate a CSV from the current DB state of the given test cases, upload to storage, and return a presigned download URL. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"exportTestCasesCsv","x-cli-name":"export-csv","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"testCaseIds":{"type":"array","example":["tc_123","tc_456"],"items":{"type":"string"},"description":"Array of test case IDs to export. Provide either `testCaseIds` or `testIds`."},"testIds":{"type":"array","example":["test_123","test_456"],"items":{"type":"string"},"description":"Array of test IDs for which to export test cases. Provide either `testCaseIds` or `testIds`."}}}}}},"responses":{"200":{"description":"CSV exported successfully","content":{"application/json":{"schema":{"type":"object","properties":{"downloadUrl":{"type":"string","description":"Presigned URL to download the CSV file"}}}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/testCases/{id}":{"get":{"tags":["test-cases"],"summary":"Get test case by ID","description":"Get a specific test case by ID. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"getTestCaseById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Test case ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Test case retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestCase"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Test case not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["test-cases"],"summary":"Update test case","description":"Update an existing test case. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"updateTestCase","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Test case ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestCase"}}}},"responses":{"200":{"description":"Test case updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestCase"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Test case not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["test-cases"],"summary":"Delete test case","description":"Soft delete a test case. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"deleteTestCase","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Test case ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Test case deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Test case not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/testCases/batch":{"delete":{"tags":["test-cases"],"summary":"Delete multiple test cases","description":"Soft delete multiple test cases by their IDs. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"deleteTestCases","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of test case IDs to delete"}}}}}},"responses":{"204":{"description":"Test cases deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions":{"get":{"tags":["sessions"],"summary":"Get sessions","description":"Get list of sessions with pagination and filtering. See [Sessions](https://docs.galtea.ai/concepts/product/version/session).","operationId":"getSessions","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by session IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"customIds","in":"query","style":"form","explode":true,"description":"Filter by session custom IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"testIds","in":"query","style":"form","explode":true,"description":"Filter by test IDs (include only). Use an empty string (\"\") to select sessions without a test","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"excludeTestIds","in":"query","style":"form","explode":true,"description":"Omit sessions linked to the specified test IDs. Use an empty string (\"\") to omit sessions without a test","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"versionIds","in":"query","style":"form","explode":true,"description":"Filter by version IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"monitorIds","in":"query","style":"form","explode":true,"description":"Filter by monitor IDs (returns only sessions scored by the given monitors)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"testCaseIds","in":"query","style":"form","explode":true,"description":"Filter by test case IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"isProduction","in":"query","description":"Filter by the session's `isProduction` flag. Prefer this over the legacy `testIds`/`excludeTestIds` empty-string trick.","required":false,"schema":{"type":"boolean"}},{"name":"statuses","in":"query","style":"form","explode":true,"description":"Filter by session statuses. Multiple values combine as OR.","required":false,"schema":{"type":"array","items":{"type":"string","enum":["PENDING","COMPLETED","FAILED"]}}},{"name":"commentLabels","in":"query","style":"form","explode":true,"description":"Filter by comment state. `__any__` matches sessions with at least one comment, `__none__` matches sessions with no comment, and any other value matches sessions with a comment carrying that label. All values combine as OR, so `__none__` plus a label returns sessions that have no comment OR carry that label.","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter sessions created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter sessions created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Sessions retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Session"}}}}},"400":{"description":"Missing required filter. Provide at least one of the scoping filters (e.g. productIds, versionIds, ids)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["sessions"],"summary":"Create session","description":"Create a new session. See [Sessions](https://docs.galtea.ai/concepts/product/version/session).","operationId":"createSession","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionInput"}}}},"responses":{"201":{"description":"Session created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"400":{"description":"\"id\" was provided in the request body. Use \"customId\" instead; \"id\" is server-generated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions/{id}":{"get":{"tags":["sessions"],"summary":"Get session by ID","description":"Get a specific session by ID. See [Sessions](https://docs.galtea.ai/concepts/product/version/session).","operationId":"getSessionById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session retrieved successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["sessions"],"summary":"Update session","description":"Update an existing session. See [Sessions](https://docs.galtea.ai/concepts/product/version/session).","operationId":"updateSession","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"responses":{"200":{"description":"Session updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["sessions"],"summary":"Delete session","description":"Soft delete a session. See [Sessions](https://docs.galtea.ai/concepts/product/version/session).","operationId":"deleteSession","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Session deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions/{id}/compatible-metrics":{"get":{"tags":["sessions"],"summary":"List metrics annotated with compatibility for a session","description":"Returns evaluable metrics annotated with whether they can be satisfied by the session's product metadata and conversation endpoint connection output mapping, plus a `relevance` ranking derived from the session's test case's test (`linked`/`matching`/`none`). Production (monitoring) sessions have no test case, so every metric is `none`. Trace-dependent and runtime-only params are out of scope and treated as always satisfied.","operationId":"listCompatibleMetricsBySession","x-cli-name":"list-compatible-metrics","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Session ID to evaluate compatibility against","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of metrics to return (default 100)","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"List of metrics with compatibility annotations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CompatibleMetric"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions/{id}/finish":{"patch":{"tags":["sessions"],"summary":"Finish session","description":"Marks a session as COMPLETED (stoppingReason provided) or FAILED (error provided). At least one of stoppingReason or error must be provided. See [Sessions](https://docs.galtea.ai/concepts/product/version/session).","operationId":"finishSession","x-cli-name":"finish","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"stoppingReason":{"type":"string","description":"Reason the session stopped (sets status to COMPLETED)","example":"GOAL_ACHIEVED"},"error":{"type":"string","description":"Error message (sets status to FAILED)"}}}}}},"responses":{"200":{"description":"Session finished successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"400":{"description":"Neither stoppingReason nor error provided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions/batch":{"delete":{"tags":["sessions"],"summary":"Delete multiple sessions","description":"Soft delete multiple sessions by their IDs. See [Sessions](https://docs.galtea.ai/concepts/product/version/session).","operationId":"deleteSessions","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of session IDs to delete"}}}}}},"responses":{"204":{"description":"Sessions deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inferenceResults":{"get":{"tags":["inference-results"],"summary":"Get inference results","description":"Get list of inference results with pagination and filtering. See [Inference Results](https://docs.galtea.ai/concepts/product/version/session/inference-result).","operationId":"getInferenceResults","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by inference result IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"sessionIds","in":"query","style":"form","explode":true,"description":"Filter by session IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"evaluationIds","in":"query","style":"form","explode":true,"description":"Filter by evaluation IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter inference results created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter inference results created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"Inference results retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InferenceResult"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["inference-results"],"summary":"Create inference result","description":"Create a new inference result. Identify the session with exactly one of `sessionId` or `sessionCustomId`. With `sessionCustomId` (your own conversation id) an existing session with that custom id is found and appended to: provide either `versionId` or `productId` as the anchor (if both are given, `versionId` wins). The session must already exist — create it first through the sessions API with that `custom_id`. If no matching session exists, the call is rejected with a 400. See [Inference Results](https://docs.galtea.ai/concepts/product/version/session/inference-result).\n","operationId":"createInferenceResult","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","description":"ID of the session. Provide this or `sessionCustomId`.","example":"session_123"},"sessionCustomId":{"type":"string","description":"Your own conversation id. An existing session with this custom id is found and appended to; if none matches the call returns a 400, so create the session first through the sessions API. Requires `versionId` or `productId`. Provide this or `sessionId`.\n","example":"my-conversation-42"},"versionId":{"type":"string","description":"Version anchor for the `sessionCustomId` lookup. Provide this or `productId`; if both are given, `versionId` wins.\n","example":"ver_123"},"productId":{"type":"string","description":"Product anchor for the `sessionCustomId` lookup when no `versionId` is given: the existing session with that custom id is found across the product's versions.\n","example":"prod_123"},"userId":{"type":"string","nullable":true,"description":"ID of the user","example":"user_123"},"index":{"type":"integer","description":"Index of the inference result","example":0},"status":{"type":"string","enum":["PENDING","GENERATED","FAILED","SKIPPED"],"description":"Status of the inference result"},"error":{"type":"string","nullable":true,"description":"Error message explaining why this inference result failed or was skipped"},"input":{"type":"object","nullable":true,"description":"Structured input data. For plain text, use { user_message: \"...\" }"},"actualOutput":{"oneOf":[{"type":"string"},{"type":"object"}],"nullable":true,"description":"Agent output. Plain text by default (the scored scalar); for voice, an envelope { assistant_message, content: [{ type, uri, transcript }] } carrying audio parts. An audio part without a transcript is rejected with a 400.","example":"Model response text"},"retrievalContext":{"type":"string","nullable":true,"description":"Retrieval context information","example":"Retrieved context document"},"latency":{"type":"number","nullable":true,"description":"Latency in milliseconds"},"inputTokens":{"type":"integer","nullable":true,"description":"Number of input tokens"},"outputTokens":{"type":"integer","nullable":true,"description":"Number of output tokens"},"cacheReadInputTokens":{"type":"integer","nullable":true,"description":"Number of cache read input tokens"},"tokens":{"type":"integer","nullable":true,"description":"Total number of tokens"},"costPerInputToken":{"type":"number","nullable":true,"description":"Cost per input token"},"costPerOutputToken":{"type":"number","nullable":true,"description":"Cost per output token"},"costPerCacheReadInputToken":{"type":"number","nullable":true,"description":"Cost per cache read input token"},"cost":{"type":"number","nullable":true,"description":"Total cost"},"conversationSimulatorVersion":{"type":"string","nullable":true,"description":"Version of the conversation simulator"}}}}}},"responses":{"201":{"description":"Inference result created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InferenceResult"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inferenceResults/aggregatedData":{"get":{"tags":["inference-results"],"summary":"Get aggregated performance data","description":"Get aggregated performance metrics data. See [Inference Results](https://docs.galtea.ai/concepts/product/version/session/inference-result).","operationId":"getAggregatedData","x-cli-name":"get-aggregated-data","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by inference result IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"organizationIds","in":"query","style":"form","explode":true,"description":"Filter by organization IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"versionIds","in":"query","style":"form","explode":true,"description":"Filter by version IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"sessionIds","in":"query","style":"form","explode":true,"description":"Filter by session IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"testIds","in":"query","style":"form","explode":true,"description":"Filter by test IDs (include only). Use an empty string (\"\") to select inference results from sessions without a test","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"excludeTestIds","in":"query","style":"form","explode":true,"description":"Omit inference results from sessions linked to the specified test IDs. Use an empty string (\"\") to omit inference results from sessions without a test","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"isProduction","in":"query","description":"Filter by the joined `Session.isProduction` flag.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Aggregated data retrieved successfully","content":{"application/json":{"schema":{"type":"object","description":"Aggregated inference result data with evaluation scores"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inferenceResults/{id}":{"get":{"tags":["inference-results"],"summary":"Get inference result by ID","description":"Get a specific inference result by ID. See [Inference Results](https://docs.galtea.ai/concepts/product/version/session/inference-result).","operationId":"getInferenceResultById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Inference result ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Inference result retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InferenceResult"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Inference result not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["inference-results"],"summary":"Update inference result","description":"Update an existing inference result. See [Inference Results](https://docs.galtea.ai/concepts/product/version/session/inference-result).","operationId":"updateInferenceResult","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Inference result ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"actualOutput":{"oneOf":[{"type":"string"},{"type":"object"}],"nullable":true,"description":"Agent output. Plain text by default (the scored scalar); for voice, an envelope { assistant_message, content: [{ type, uri, transcript }] } carrying audio parts. An audio part without a transcript is rejected with a 400.","example":"Model response text"},"retrievalContext":{"type":"string","example":"Retrieved context document"},"error":{"type":"string","nullable":true,"description":"Error message explaining why this inference result failed or was skipped"},"latency":{"type":"integer"}}}}}},"responses":{"200":{"description":"Inference result updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InferenceResult"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Inference result not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["inference-results"],"summary":"Delete inference result","description":"Soft delete an inference result. See [Inference Results](https://docs.galtea.ai/concepts/product/version/session/inference-result).","operationId":"deleteInferenceResult","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Inference result ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Inference result deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Inference result not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inferenceResults/batch":{"post":{"tags":["inference-results"],"summary":"Create inference results batch","description":"Create multiple inference results from conversation turns. Identify the session with exactly one of `sessionId` or `sessionCustomId` (same find-existing semantics as `POST /inferenceResults`). See [Inference Results](https://docs.galtea.ai/concepts/product/version/session/inference-result).\n","operationId":"createInferenceResultsBatch","x-cli-name":"create-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["conversationTurns"],"properties":{"sessionId":{"type":"string","description":"ID of the session. Provide this or `sessionCustomId`.","example":"session_123"},"sessionCustomId":{"type":"string","description":"Your own conversation id. An existing session with this custom id is found and appended to; if none matches the call returns a 400, so create the session first through the sessions API. Requires `versionId` or `productId`. Provide this or `sessionId`.\n","example":"my-conversation-42"},"versionId":{"type":"string","description":"Version anchor for the `sessionCustomId` lookup. Provide this or `productId`; if both are given, `versionId` wins.\n","example":"ver_123"},"productId":{"type":"string","description":"Product anchor for the `sessionCustomId` lookup when no `versionId` is given: the existing session with that custom id is found across the product's versions.\n","example":"prod_123"},"conversationTurns":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"201":{"description":"Inference results created successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InferenceResult"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["inference-results"],"summary":"Delete multiple inference results","description":"Soft delete multiple inference results by their IDs. See [Inference Results](https://docs.galtea.ai/concepts/product/version/session/inference-result).","operationId":"deleteInferenceResults","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of inference result IDs to delete"}}}}}},"responses":{"204":{"description":"Inference results deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inferenceResults/generate":{"post":{"tags":["inference-results"],"summary":"Generate inference results from test cases","description":"Triggers async inference generation for specified test cases using the version's endpoint connection. Provide either `versionId` or `productId`. When `productId` is given without a `versionId`, the product's latest properly configured version (one with a conversation-endpoint, phone, or WebRTC connection) is cloned and inferences run against the clone; the product must already have such a version. Omitting `versionId` clones a version, so it requires permission to create versions (a caller lacking it gets a 403). See [Inference Results](https://docs.galtea.ai/concepts/product/version/session/inference-result).\n","operationId":"generateInferenceResults","x-cli-name":"generate","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"testIds":{"type":"array","example":["test_123","test_456"],"items":{"type":"string"},"description":"Array of test IDs to generate inferences for (will process all test cases in these tests)"},"testCaseIds":{"type":"array","example":["tc_123","tc_456"],"items":{"type":"string"},"description":"Array of test case IDs to generate inferences for"},"versionId":{"type":"string","description":"Version ID containing the endpoint connection configuration. Provide this or `productId`.","example":"ver_123"},"productId":{"type":"string","description":"Product ID to run against when no `versionId` is given. The product's latest properly configured version is cloned and inferences run against the clone.\n","example":"prod_123"},"metricIds":{"type":"array","example":["metric_123","metric_456"],"items":{"type":"string"},"description":"Optional array of metric IDs to evaluate after inference generation. If provided, evaluations will be triggered automatically."}}}}}},"responses":{"202":{"description":"Inference generation job queued successfully","content":{"application/json":{"schema":{"type":"object","properties":{"jobId":{"type":"string"},"versionId":{"type":"string","description":"The version the job runs against — the passed `versionId`, or the id of the clone created when only `productId` was given."},"message":{"type":"string"},"testCaseCount":{"type":"integer"}}}}}},"400":{"description":"Bad request - missing required parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/traces":{"get":{"tags":["traces"],"summary":"Get traces","description":"Get a list of traces with filtering and pagination. See [Traces](https://docs.galtea.ai/sdk/api/trace/service).","operationId":"getTraces","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by trace IDs","schema":{"type":"array","items":{"type":"string"}}},{"name":"inferenceResultIds","in":"query","style":"form","explode":true,"description":"Filter by inference result IDs","schema":{"type":"array","items":{"type":"string"}}},{"name":"sessionIds","in":"query","style":"form","explode":true,"description":"Filter by session IDs (via inference result relationship)","schema":{"type":"array","items":{"type":"string"}}},{"name":"types","in":"query","style":"form","explode":true,"description":"Filter by trace types (SPAN, GENERATION, EVENT, AGENT, TOOL, CHAIN, RETRIEVER, EVALUATOR, EMBEDDING, GUARDRAIL)","schema":{"type":"array","items":{"type":"string","enum":["SPAN","GENERATION","EVENT","AGENT","TOOL","CHAIN","RETRIEVER","EVALUATOR","EMBEDDING","GUARDRAIL"]}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by trace names","schema":{"type":"array","items":{"type":"string"}}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort format createdAt,asc or createdAt,desc","schema":{"type":"array","items":{"type":"string"}}},{"name":"offset","in":"query","description":"Number of items to skip","schema":{"type":"integer"}},{"name":"limit","in":"query","description":"Maximum number of items to return","schema":{"type":"integer"}},{"name":"fromStartTime","in":"query","description":"Filter traces started at or after this timestamp (ISO 8601 format)","schema":{"type":"string","format":"date-time"}},{"name":"toStartTime","in":"query","description":"Filter traces started at or before this timestamp (ISO 8601 format)","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Traces retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Trace"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["traces"],"summary":"Create trace","description":"Create a new trace for a tool/function call. See [Traces](https://docs.galtea.ai/sdk/api/trace/service).","operationId":"createTrace","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["inferenceResultId","name"],"properties":{"inferenceResultId":{"type":"string","example":"ir_123"},"name":{"type":"string","example":"Example Name"},"type":{"type":"string","enum":["SPAN","GENERATION","EVENT","AGENT","TOOL","CHAIN","RETRIEVER","EVALUATOR","EMBEDDING","GUARDRAIL"]},"inputData":{"type":"object"},"outputData":{"oneOf":[{"type":"object"},{"type":"string"}]},"error":{"type":"string","example":"Error message"},"latencyMs":{"type":"number"},"metadata":{"type":"object"}}}}}},"responses":{"200":{"description":"Trace created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Trace"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/traces/{id}":{"get":{"tags":["traces"],"summary":"Get trace by ID","description":"Get a specific trace by its ID. See [Traces](https://docs.galtea.ai/sdk/api/trace/service).","operationId":"getTraceById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Trace ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Trace"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Trace not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["traces"],"summary":"Delete trace","description":"Soft delete a trace by its ID. See [Traces](https://docs.galtea.ai/sdk/api/trace/service).","operationId":"deleteTrace","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Trace ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Trace deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Trace not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/traces/batch":{"post":{"tags":["traces"],"summary":"Create traces batch","description":"Create multiple traces in a single API call (transactional). See [Traces](https://docs.galtea.ai/sdk/api/trace/service).","operationId":"createTracesBatch","x-cli-name":"create-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["inferenceResultId","name"],"properties":{"id":{"type":"string","description":"Optional custom trace ID","example":"id_123"},"inferenceResultId":{"type":"string","description":"ID of the inference result this trace belongs to","example":"ir_123"},"name":{"type":"string","description":"Name of the trace"},"description":{"example":"Example Name","type":"string","nullable":true,"description":"Optional description of the trace"},"type":{"type":"string","enum":["SPAN","GENERATION","EVENT","AGENT","TOOL","CHAIN","RETRIEVER","EVALUATOR","EMBEDDING","GUARDRAIL"],"nullable":true,"description":"Type of trace"},"inputData":{"type":"object","nullable":true,"description":"Input data for the trace"},"outputData":{"oneOf":[{"type":"object"},{"type":"string"}],"nullable":true,"description":"Output data from the trace (an object, or a plain string)"},"error":{"type":"string","nullable":true,"description":"Error message if the trace failed","example":"Error message"},"latencyMs":{"type":"number","nullable":true,"description":"Duration in milliseconds"},"metadata":{"type":"object","nullable":true,"description":"Additional trace attributes"},"parentTraceId":{"type":"string","nullable":true,"description":"Parent trace ID for hierarchical traces (references id of another trace in batch)"},"startTime":{"type":"string","format":"date-time","nullable":true,"description":"Start time of the trace"},"endTime":{"type":"string","format":"date-time","nullable":true,"description":"End time of the trace"}}}}}}},"responses":{"200":{"description":"Traces created successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Trace"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["traces"],"summary":"Delete multiple traces","description":"Soft delete multiple traces by their IDs. See [Traces](https://docs.galtea.ai/sdk/api/trace/service).","operationId":"deleteTraces","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of trace IDs to delete"}}}}}},"responses":{"204":{"description":"Traces deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/fromSession":{"post":{"tags":["evaluations"],"summary":"Create evaluations from session","description":"Create evaluations from a session. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"createEvaluationsFromSession","x-cli-name":"create-from-session","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId"],"properties":{"metrics":{"type":"array","description":"Metrics to evaluate. Optional if specificationIds is provided or the product has specifications with linked metrics.","items":{"type":"object","properties":{"id":{"type":"string","example":"id_123"},"name":{"type":"string","example":"Example Name"},"score":{"type":"number","example":0.95}}}},"sessionId":{"type":"string","example":"session_123"},"specificationIds":{"type":"array","description":"Specification IDs whose linked metrics will be evaluated. Can be combined with metrics; the API merges and deduplicates.","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Evaluations created successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Evaluation"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/fromSessions":{"post":{"tags":["evaluations"],"summary":"Evaluate multiple sessions in one call","description":"Batch-evaluate existing sessions in a single call. Pick exactly one mode: (a) `sessionIds` — explicit list of session IDs; (b) `versionId` — every session attached to that version. Each selected session is evaluated by the same logic as `POST /evaluations/fromSession`, so the inference results that already live on the session are scored. Unlike `POST /evaluations/fromVersion`, this endpoint does NOT require a conversation endpoint connection on the version — use it when the inferences already exist (e.g. imported traces). Metric scope: if you send `metrics`, they are applied to every session. If you do not send `metrics`, each session is scored only by the metrics of its own originating specification (the spec that produced its test case), never the union of all the product's metrics. When you send `specificationIds`, they act as a strict allow-list: a session is evaluated only if its own spec is in the list; sessions whose spec is not listed — and imported sessions that have no spec — are skipped and reported in `message`. Use `POST /evaluations/fromSession` for a single session. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).\n","operationId":"createEvaluationsFromSessions","x-cli-name":"create-from-sessions","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Exactly one of `sessionIds` or `versionId` is required.","properties":{"sessionIds":{"type":"array","description":"Explicit list of session IDs to evaluate. Mutually exclusive with versionId.","items":{"type":"string"},"example":["ses_123","ses_456"]},"versionId":{"type":"string","description":"Evaluate every session attached to this version. Mutually exclusive with sessionIds.","example":"ver_123"},"metrics":{"type":"array","description":"Metrics to evaluate. When provided, these exact metrics are applied to every session and per-specification scoping is bypassed. Optional: if omitted, each session is scored by the metrics of its own originating specification.\n","items":{"type":"object","properties":{"id":{"type":"string","example":"metric_123"},"name":{"type":"string","example":"Example Name"},"score":{"type":"number","example":0.95}}}},"specificationIds":{"type":"array","description":"Specification IDs used to scope evaluation. If `metrics` is omitted, this is a strict allow-list: each session is evaluated only when its own originating specification is in the list, using just that spec's linked metrics; sessions whose spec is not listed (and imported sessions with no spec) are skipped. If `metrics` is also provided, the explicit metrics apply to every session and these specs' metrics are merged in (additive), with no per-session scoping.\n","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Batch evaluation processed","content":{"application/json":{"schema":{"type":"object","properties":{"sessionsEvaluated":{"type":"integer","description":"Number of sessions whose evaluations were dispatched successfully. Sessions skipped during per-specification scoping are counted in neither this nor sessionsFailed. A session is skipped when its originating specification is outside the requested `specificationIds`, or when that specification has no linked metrics (which can happen even with no `specificationIds` filter). The count of skipped sessions and the reason for each cause are reported in `message`.\n"},"sessionsFailed":{"type":"integer","description":"Number of sessions whose evaluation failed."},"evaluationsCreated":{"type":"integer","description":"Total number of Evaluation records created across all successful sessions."},"failures":{"type":"array","description":"Per-session failure details.","items":{"type":"object","properties":{"sessionId":{"type":"string"},"error":{"type":"string"}}}},"message":{"type":"string","description":"Human-readable summary. Reports how many sessions were evaluated, failed, and skipped during per-specification scoping, naming each skip cause with its own count and reason (outside the requested `specificationIds`, or no linked metrics), plus any truncation note.\n"},"totalSessionsAvailable":{"type":"integer","nullable":true,"description":"Total sessions matching the request (versionId mode only). When greater than the count actually evaluated the response was truncated to the first 1000 rows; the caller can re-issue the request with explicit `sessionIds` to cover the remainder. `null` in `sessionIds` mode.\n"},"truncated":{"type":"boolean","description":"True when the version had more sessions than the per-request page limit (1000)."}}}}}},"400":{"description":"Bad request — malformed input (e.g. both `sessionIds` and `versionId` provided, neither provided, empty `sessionIds`, wrong types) or a `versionId` that exists but has zero sessions to evaluate.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"One or more of the requested entities was not found: the `versionId` does not exist or is not visible to the caller, or one or more `sessionIds` do not exist or are not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/fromInferenceResult":{"post":{"tags":["evaluations"],"summary":"Create evaluations for a single inference result","description":"Create evaluations for a specific turn in a conversation. This is useful for production monitoring where you want to evaluate turn-by-turn performance. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"createEvaluationsFromInferenceResult","x-cli-name":"create-from-inference-result","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["inferenceResultId"],"properties":{"metrics":{"type":"array","description":"Metrics to evaluate. Optional if specificationIds is provided or the product has specifications with linked metrics.","items":{"type":"object","properties":{"id":{"type":"string","example":"id_123"},"name":{"type":"string","example":"Example Name"},"score":{"type":"number","example":0.95}}}},"inferenceResultId":{"type":"string","description":"The ID of the inference result (turn) to evaluate","example":"ir_123"},"specificationIds":{"type":"array","description":"Specification IDs whose linked metrics will be evaluated. Can be combined with metrics; the API merges and deduplicates.","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Evaluations created successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Evaluation"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Inference result not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/singleTurn":{"post":{"tags":["evaluations"],"summary":"Create single-turn evaluations","description":"Create evaluations for single-turn interactions. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"createSingleTurnEvaluations","x-cli-name":"create-single-turn","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metrics","actualOutput"],"properties":{"metrics":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"id_123"},"name":{"type":"string","example":"Example Name"},"score":{"type":"number","example":0.95}}}},"versionId":{"type":"string","description":"Version to attach the evaluation to. Optional: when omitted, provide productId and the API reuses the product's latest version (creating a default first version if the product has none). One of versionId or productId is required.","example":"ver_123"},"productId":{"type":"string","description":"Product to anchor the evaluation when versionId is omitted. Ignored when versionId is provided.","example":"prod_123"},"testCaseId":{"type":"string","description":"Required when isProduction is false. Must be omitted when isProduction is true.","example":"tc_123"},"actualOutput":{"type":"string","example":"Model response text"},"input":{"type":"string","description":"User input/prompt. Required when isProduction is true. Must be omitted when isProduction is false.","example":"What is the capital of France?"},"retrievalContext":{"type":"string","description":"RAG retrieval context used to generate the actual output","example":"Retrieved context document"},"isProduction":{"type":"boolean","description":"When true, creates a production evaluation (input required, testCaseId must be omitted). When false (default), testCaseId is required and input must be omitted."}}}}}},"responses":{"201":{"description":"Evaluations created successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Evaluation"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/retry":{"post":{"tags":["evaluations"],"summary":"Retry failed evaluations","description":"Retry one or more failed evaluations. Non-admin users are limited by EVALUATION_MAX_RETRIES. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"retryEvaluations","x-cli-name":"retry","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of evaluation IDs to retry"}}}}}},"responses":{"202":{"description":"Retry request accepted","content":{"application/json":{"schema":{"type":"object","properties":{"retried":{"type":"integer","description":"Number of evaluations successfully queued for retry"},"skipped":{"type":"integer","description":"Number of evaluations skipped (not FAILED or exceeded max retries)"},"errors":{"type":"array","items":{"type":"string"},"description":"Error messages for failed retries"}}}}}},"400":{"description":"Bad request - invalid evaluation IDs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/fromVersion":{"post":{"tags":["evaluations"],"summary":"Evaluate a version","description":"Automatically evaluates a version by resolving its product's specifications, their linked metrics, and their linked tests. Creates inference generation jobs for every test case across all linked tests. Specifications without tests or without metrics are silently skipped. Provide either `versionId` or `productId`. When `productId` is given without a `versionId`, the product's latest properly configured version (one with a conversation-endpoint, phone, or WebRTC connection) is cloned and the evaluation runs against the clone; the product must already have such a version. Omitting `versionId` clones a version, so it requires permission to create versions (a caller lacking it gets a 403). See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).\n","operationId":"evaluateVersion","x-cli-name":"create-from-version","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"versionId":{"type":"string","description":"The version ID to evaluate. Provide this or `productId`.","example":"ver_123"},"productId":{"type":"string","description":"Product ID to evaluate when no `versionId` is given. The product's latest properly configured version is cloned and the evaluation runs against the clone.\n","example":"prod_123"},"specificationIds":{"type":"array","description":"Optional list of specification IDs to evaluate. If omitted, all product specifications with linked metrics and tests are used.","example":["spec_123","spec_456"],"items":{"type":"string"}}}}}}},"responses":{"202":{"description":"Evaluation job queued successfully","content":{"application/json":{"schema":{"type":"object","properties":{"jobId":{"type":"string"},"versionId":{"type":"string","description":"The version the job runs against — the passed `versionId`, or the id of the clone created when only `productId` was given."},"testCaseCount":{"type":"integer"},"message":{"type":"string"},"specifications":{"type":"array","description":"Summary of specifications that were evaluated","items":{"type":"object","properties":{"specificationId":{"type":"string"},"testCount":{"type":"integer"},"metricCount":{"type":"integer"}}}}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Version not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/fromMetrics":{"post":{"tags":["evaluations"],"summary":"Replay evaluations onto a new metric revision","description":"Re-runs historical evaluations that used any metric in `metricGroupId` against the new metric revision `newMetricId`, scoped to the given products. Idempotent: any `(sessionId, inferenceResultId)` pair that already has an evaluation on `newMetricId` is skipped.\n","operationId":"evaluateFromMetrics","x-cli-name":"replay-from-metrics","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["newMetricId","metricGroupId","productIds"],"properties":{"newMetricId":{"type":"string","example":"metric_123"},"metricGroupId":{"type":"string","example":"group_123"},"productIds":{"type":"array","items":{"type":"string"},"example":["prod_1","prod_2"]}}}}}},"responses":{"202":{"description":"Replay job accepted","content":{"application/json":{"schema":{"type":"object","properties":{"scheduled":{"type":"integer"},"skipped":{"type":"integer"},"errors":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Invalid body or metricGroupId does not match the metric","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Metric or product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/batch":{"delete":{"tags":["evaluations"],"summary":"Delete multiple evaluations","description":"Soft delete multiple evaluations by their IDs. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"deleteEvaluations","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of evaluation IDs to delete"}}}}}},"responses":{"204":{"description":"Evaluations deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/human/pending":{"get":{"tags":["evaluations"],"summary":"Get pending human evaluations","description":"Get list of pending human evaluations that the authenticated user can evaluate based on their user groups. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"getPendingHumanEvaluations","x-cli-name":"list-pending-human","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"Pending human evaluations retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"evaluations":{"type":"array","items":{"$ref":"#/components/schemas/Evaluation"}},"total":{"type":"integer"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/human/completed":{"get":{"tags":["evaluations"],"summary":"Get completed human evaluations","description":"Get list of human evaluations completed by the authenticated user. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"getCompletedHumanEvaluations","x-cli-name":"list-completed-human","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"Completed human evaluations retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"evaluations":{"type":"array","items":{"$ref":"#/components/schemas/Evaluation"}},"total":{"type":"integer"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/{id}/claim":{"post":{"tags":["evaluations"],"summary":"Claim an evaluation for human review or annotation","description":"Claim an evaluation to prevent concurrent editing. For HUMAN_EVALUATION metrics, enforces user group permissions (admins skip). For other metrics, works as an annotation claim open to all org members. Works on any evaluation status. Sets humanEvaluatorStartedAt timestamp. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"claimHumanEvaluation","x-cli-name":"claim","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Evaluation ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Evaluation claimed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Evaluation"}}}},"400":{"description":"Evaluation is already being evaluated or not in PENDING_HUMAN status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"User not authorized to evaluate this metric","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Evaluation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/{id}/release":{"post":{"tags":["evaluations"],"summary":"Release a claimed evaluation or annotation","description":"Release a previously claimed evaluation or annotation without submitting a score. Works on any evaluation status. Clears humanEvaluatorStartedAt. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"releaseHumanEvaluation","x-cli-name":"release","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Evaluation ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Evaluation released successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Evaluation"}}}},"400":{"description":"Evaluation is not being evaluated or not claimed by this user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Evaluation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/{id}/submit":{"post":{"tags":["evaluations"],"summary":"Submit a human evaluation or annotation score","description":"Submit a score and optional reason. For HUMAN_EVALUATION metrics, enforces user group permissions and updates both score sets. For PENDING_HUMAN evaluations, also sets status to SUCCESS. For other metrics, works as an annotation — writes only humanScore/humanReason/humanEvaluatorFinishedAt, leaving AI score/reason and status untouched. Works on any evaluation status. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"submitHumanEvaluation","x-cli-name":"submit","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Evaluation ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["score"],"properties":{"score":{"type":"number","minimum":0,"maximum":1,"description":"The evaluation score (0-1)","example":0.95},"reason":{"type":"string","description":"Optional reason for the score","example":"Evaluation reason"}}}}}},"responses":{"200":{"description":"Evaluation submitted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Evaluation"}}}},"400":{"description":"Invalid score or evaluation not in PENDING_HUMAN status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"User not authorized to evaluate this metric or evaluation not claimed by this user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Evaluation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/{id}/edit-human":{"post":{"tags":["evaluations"],"summary":"Edit a submitted human evaluation","description":"Edit the score and reason for a previously submitted human evaluation. Only the original evaluator can edit. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"editHumanEvaluation","x-cli-name":"edit-human","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Evaluation ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["score"],"properties":{"score":{"type":"number","minimum":0,"maximum":1,"example":0.95},"reason":{"type":"string","example":"Evaluation reason"}}}}}},"responses":{"200":{"description":"Evaluation updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Evaluation"}}}},"400":{"description":"Invalid score or evaluation not eligible for editing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"User is not the original evaluator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Evaluation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/{id}":{"delete":{"tags":["evaluations"],"summary":"Delete evaluation","description":"Soft delete an evaluation. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","operationId":"deleteEvaluation","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Evaluation ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Evaluation deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Evaluation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"getEvaluationById","tags":["evaluations"],"summary":"Get evaluation by ID","description":"Get a specific evaluation by ID. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","security":[{"bearerAuth":[]}],"x-cli-name":"get","parameters":[{"schema":{"type":"string","description":"Evaluation ID","example":"eval_123"},"required":true,"description":"Evaluation ID","name":"id","in":"path"}],"responses":{"200":{"description":"Evaluation retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Evaluation"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Evaluation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/generateFromFewShot/augment":{"post":{"tags":["test-cases"],"summary":"Augment test cases","description":"Submit test cases for augmentation using few-shot learning. The API automatically selects up to 5 random test cases from the given test as few-shot examples. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"augmentTestCases","x-cli-name":"augment","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["testId","maxTestCases"],"properties":{"testId":{"type":"string","description":"ID of the test to augment","example":"test_123"},"maxTestCases":{"type":"integer","minimum":1,"example":100},"productDescription":{"type":"string","nullable":true,"example":"A product that helps users"}}}}}},"responses":{"202":{"description":"Augmentation task started successfully","content":{"application/json":{"schema":{"type":"object","properties":{"taskId":{"type":"string","example":"task_123"}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/generateFromFewShot/status/{taskId}":{"get":{"tags":["test-cases"],"summary":"Get augmentation task status","description":"Retrieve the status of an augmentation task. See [Tests](https://docs.galtea.ai/concepts/product/test).","operationId":"getAugmentationStatus","x-cli-name":"augmentation-status","security":[{"bearerAuth":[]}],"parameters":[{"name":"taskId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Task status retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["PENDING","IN_PROGRESS","COMPLETED","FAILED"]},"result":{"type":"object","nullable":true}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics":{"get":{"tags":["analytics"],"summary":"Get analytics data","description":"Get analytics data for a product with optional filtering. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"getAnalytics","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"productId","in":"query","description":"Product ID (required)","required":true,"schema":{"type":"string"}},{"name":"versionIds","in":"query","style":"form","explode":true,"description":"Filter by version IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"testIds","in":"query","style":"form","explode":true,"description":"Filter by test IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"metricIds","in":"query","style":"form","explode":true,"description":"Filter by metric IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"from","in":"query","description":"Start date for filtering (epoch milliseconds). Ranges wider than 1830 days (5 years) are rejected with 400.","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"End date for filtering (epoch milliseconds)","required":false,"schema":{"type":"string"}},{"name":"languages","in":"query","style":"form","explode":true,"description":"Filter by language codes","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"isProduction","in":"query","description":"When set, returns only production (true) or only development (false) data. Omit to include both.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Analytics data retrieved successfully","content":{"application/json":{"schema":{"type":"object","description":"Analytics data containing evaluation results and metrics. Each entry in `averages.total` carries a per-version `coverage` number (0-100, same scale as `score`): the percentage of the product's non-deleted test cases that have at least one completed evaluation under that version. It is 0 when the product has no test cases or the version evaluated none, and is computed independently of the `isProduction` filter.","properties":{"groups":{"type":"array","items":{"type":"object","required":["type"],"properties":{"type":{"type":"string"},"specifications":{"type":"array","description":"One entry per specification evaluated in this test-type group.","items":{"type":"object","required":["id","description","type"],"properties":{"id":{"type":"string"},"description":{"type":"string"},"type":{"type":"string"},"scores":{"type":"array","description":"Per-version score of this specification within THIS test-type group. Each item is `{ versionId, versionName, score }` with score on a 0-100 scale.","items":{"type":"object","required":["versionId","versionName","score"],"properties":{"versionId":{"type":"string"},"versionName":{"type":"string"},"score":{"type":"number"}}}},"overallScores":{"type":"array","description":"Per-version canonical overall score (each item `{ versionId, versionName, score }`, 0-100): the evaluation-count-weighted average of this specification's scores across ALL test-type groups. The Overview specification ring and the low_specification_score insight flag both read this one number, so they never disagree.","items":{"type":"object","required":["versionId","versionName","score"],"properties":{"versionId":{"type":"string"},"versionName":{"type":"string"},"score":{"type":"number"}}}}}}}}}}}}}}},"400":{"description":"Missing required productId","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics/export":{"post":{"tags":["analytics"],"summary":"Export analytics data","description":"Export analytics data for a product with optional filtering. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"exportAnalytics","x-cli-name":"export","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productId"],"properties":{"productId":{"type":"string","description":"Product ID (required)","example":"prod_123"},"versionIds":{"type":"array","items":{"type":"string"},"description":"Filter by version IDs"},"testIds":{"type":"array","example":["test_123","test_456"],"items":{"type":"string"},"description":"Filter by test IDs"},"metricIds":{"type":"array","example":["metric_123","metric_456"],"items":{"type":"string"},"description":"Filter by metric IDs"},"languages":{"type":"array","items":{"type":"string"},"description":"Filter by language codes"},"from":{"type":"string","format":"date-time","description":"Start date for filtering"},"to":{"type":"string","format":"date-time","description":"End date for filtering"},"isProduction":{"type":"boolean","description":"When set, exports only production (true) or only development (false) data. Omit to include both."}}}}}},"responses":{"200":{"description":"Analytics data exported successfully","content":{"application/json":{"schema":{"type":"object","description":"Exported analytics data"}}}},"400":{"description":"Missing required productId","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics/insights":{"get":{"tags":["analytics"],"summary":"Get analytics insights for a version","description":"Computes deterministic red flags / proactive insights (low metric scores, specification coverage gaps) for a single version, plus a fail-open LLM-generated narrative summary. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"getAnalyticsInsights","x-cli-name":"get-insights","security":[{"bearerAuth":[]}],"parameters":[{"name":"productId","in":"query","description":"Product ID (required)","required":true,"schema":{"type":"string"}},{"name":"versionId","in":"query","description":"Version ID to compute insights for (required)","required":true,"schema":{"type":"string"}},{"name":"testIds","in":"query","style":"form","explode":true,"description":"Filter by test IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"metricIds","in":"query","style":"form","explode":true,"description":"Filter by metric IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"languages","in":"query","style":"form","explode":true,"description":"Filter by language codes","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"from","in":"query","description":"Start date for filtering","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"End date for filtering","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"includeNarrative","in":"query","description":"When true (default), a fail-open LLM-generated narrative summary is computed and returned alongside the deterministic flags. When false, the narrative LLM call is skipped entirely and the response carries `narrative: null` and `narrativeGeneratedByAi: false`; the deterministic flags are unchanged. Machine consumers that produce their own prose should pass false to avoid the wasted LLM call.","required":false,"schema":{"type":"boolean","default":true}},{"name":"isProduction","in":"query","description":"When set, returns only production (true) or only development (false) data. Omit to include both.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Analytics insights computed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsInsights"}}}},"400":{"description":"Missing required productId or versionId","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics/insights/comparison":{"get":{"tags":["analytics"],"summary":"Get cross-version analytics comparison insights","description":"Computes deterministic red flags / proactive insights across versions (metric degradation, metric improvement, cost outlier, latency outlier), plus a fail-open LLM-generated narrative summary. When versionIds is omitted, all versions present in the analytics data are compared. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"compareAnalyticsInsights","x-cli-name":"compare-insights","security":[{"bearerAuth":[]}],"parameters":[{"name":"productId","in":"query","description":"Product ID (required)","required":true,"schema":{"type":"string"}},{"name":"versionIds","in":"query","style":"form","explode":true,"description":"Version IDs to compare. When omitted, all versions present in the analytics data are compared.","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"testIds","in":"query","style":"form","explode":true,"description":"Filter by test IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"metricIds","in":"query","style":"form","explode":true,"description":"Filter by metric IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"languages","in":"query","style":"form","explode":true,"description":"Filter by language codes","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"from","in":"query","description":"Start date for filtering","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"End date for filtering","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"includeNarrative","in":"query","description":"When true (default), a fail-open LLM-generated narrative summary is computed and returned alongside the deterministic flags. When false, the narrative LLM call is skipped entirely and the response carries `narrative: null` and `narrativeGeneratedByAi: false`; the deterministic flags are unchanged. Machine consumers that produce their own prose should pass false to avoid the wasted LLM call.","required":false,"schema":{"type":"boolean","default":true}},{"name":"isProduction","in":"query","description":"When set, returns only production (true) or only development (false) data. Omit to include both.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Cross-version analytics comparison insights computed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsInsightsComparison"}}}},"400":{"description":"Missing required productId","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/storage/generate-put-presigned-url":{"get":{"tags":["storage"],"summary":"Generate upload presigned URL","description":"Generate a presigned URL for uploading files to storage. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"generatePutPresignedUrl","x-cli-name":"generate-put-url","security":[{"bearerAuth":[]}],"parameters":[{"name":"key","in":"query","description":"Storage key","required":true,"schema":{"type":"string"}},{"name":"fileType","in":"query","description":"File type (default: groundTruth)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Presigned URL generated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/storage/generate-get-presigned-url":{"get":{"tags":["storage"],"summary":"Generate download presigned URL","description":"Generate a presigned URL for downloading files from storage. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"generateGetPresignedUrl","x-cli-name":"generate-get-url","security":[{"bearerAuth":[]}],"parameters":[{"name":"uri","in":"query","description":"Storage URI","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Presigned URL generated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluatorModels":{"get":{"tags":["evaluator-models"],"summary":"Get evaluator models","description":"Get list of evaluator models with filtering options. See [Models](https://docs.galtea.ai/concepts/model).","operationId":"getEvaluatorModels","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by model names (exact match)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by model name (case-insensitive contains)","required":false,"schema":{"type":"string"}},{"name":"selectable","in":"query","description":"Filter by selectable models","required":false,"schema":{"type":"boolean"}},{"name":"enabled","in":"query","description":"Filter by enabled models","required":false,"schema":{"type":"boolean"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Evaluator models retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EvaluatorModel"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/conversationSimulator/generateNextUserMessage":{"post":{"tags":["sessions"],"summary":"Generate next user message","description":"Simulate the next user message in a conversation based on the provided scenario and turns. See [Sessions](https://docs.galtea.ai/concepts/product/version/session).","operationId":"generateNextUserMessage","x-cli-name":"generate-message","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scenario":{"type":"string","example":"Customer support"},"turns":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"Next user message generated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"The generated next user message"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/minimum-sdk-version":{"get":{"summary":"Get minimum SDK version","description":"Get minimum supported SDK version of the API and latest published version. See [Platform Overview](https://docs.galtea.ai/introduction).","operationId":"getMinimumSdkVersion","x-cli-name":"minimum-sdk-version","responses":{"200":{"description":"SDK version information retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"latestSdkVersionPublished":{"type":"string","example":"1.0.0"},"minimumSdkVersionSupported":{"type":"string","example":"0.9.0"}}}}}}}}},"/jobs/{jobId}/status":{"get":{"tags":["jobs"],"summary":"Get job status","description":"Retrieve the status of an async job (e.g., inference generation). Returns the job state, progress, result, and any error information.\n\nTenant isolation: a job is only visible to users in the same organization as the user who dispatched it.\nCross-tenant reads receive `404` (rather than `403`) to avoid leaking the existence of jobs in other organizations.\nSystem jobs (those without an owning user) are never exposed through this endpoint.\n","operationId":"getJobStatus","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"},"description":"The ID of the job to check"}],"responses":{"200":{"description":"Job status retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The job ID"},"state":{"type":"string","description":"The current state of the job. `cancelled` is surfaced once the user\ncalls `POST /jobs/{jobId}/cancel`; it is distinct from `failed`,\nwhich is reserved for unintentional errors.\n","enum":["waiting","active","completed","failed","delayed","prioritized","waiting-children","cancelled"]},"progress":{"oneOf":[{"type":"number"},{"type":"object"}],"description":"Job progress (0-100 or custom object)"},"result":{"type":"object","nullable":true,"description":"The job result when completed (e.g., sessionResults, inferenceResultIds, failedTestCaseIds)"},"error":{"type":"string","nullable":true,"description":"Error message if the job failed"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Job not found, or the job is owned by a different organization (intentionally indistinguishable to avoid leaking existence).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs/{jobId}/cancel":{"post":{"tags":["jobs"],"summary":"Cancel a job","description":"Cancel a queued or in-flight async job (e.g., inference generation). Use this to\nstop a doomed batch instead of waiting for every unit to fail individually.\n\nBehaviour:\n- A queued or delayed job is removed from the queue and will never run.\n- An in-flight job receives a cooperative-cancellation signal: the worker\n  observes it at its next checkpoint and stops dispatching further work\n  (for inference generation, this means no further sessions are created).\n  Work already in progress when the signal is observed is NOT rolled back —\n  sessions that have already been created remain. Subsequent reads of\n  `GET /jobs/{jobId}/status` will surface the distinct `cancelled` state.\n- The in-flight guarantee applies only to handlers that implement the\n  cooperative-cancellation checkpoint. Today that is inference generation;\n  other job types (e.g. trace imports) do not yet observe the cancel signal\n  and will run to completion even though the cancel call returns 200 and the\n  status read flips to `cancelled`. Trace imports are short, so this is a\n  deliberate Phase-1 trade-off rather than a correctness issue.\n\nTenant isolation: only users in the dispatching user's organization may\ncancel a job. Cross-tenant cancels return `404` (not `403`) to avoid leaking\nthe existence of jobs in other organizations — matching `GET /jobs/{jobId}/status`.\n","operationId":"cancelJob","x-cli-name":"cancel","security":[{"bearerAuth":[]}],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"},"description":"The ID of the job to cancel"}],"responses":{"200":{"description":"Cancellation accepted. Either the job was queued and has been removed, or an in-flight job has been signalled to stop. Repeated cancels are idempotent and also return 200.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The job ID"},"state":{"type":"string","description":"Terminal state surfaced to the caller.","enum":["cancelled"]}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Job not found, or the job is owned by a different organization (intentionally indistinguishable to avoid leaking existence).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The job is already in a terminal state (`completed` or `failed`) and cannot be cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/otel/auth":{"post":{"tags":["traces"],"summary":"Validate credentials for OTel ingestion","description":"Validates the customer's API key and returns the user ID via x-customer-id header.\nUsed by the Istio gateway ext-authz filter to authenticate OTel data ingestion requests.\n","operationId":"otelAuth","x-cli-name":"otel-auth","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Credentials are valid","headers":{"x-customer-id":{"description":"The authenticated user's ID","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/otel/traces":{"post":{"tags":["traces"],"summary":"Ingest OTLP/JSON traces","description":"Receives an OTLP/JSON trace payload and persists spans as Galtea Trace records. Authenticated via standard API key (processAccessTokenMiddleware); the authenticated user is the tenant and RBAC applies. Any payload customer.id resource attribute is ignored on this public path.\n","operationId":"ingestOtelTraces","x-cli-name":"ingest-otel","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["resourceSpans"],"properties":{"resourceSpans":{"type":"array","items":{"type":"object","properties":{"resource":{"type":"object","properties":{"attributes":{"type":"array","items":{"type":"object"}}}},"scopeSpans":{"type":"array","items":{"type":"object","properties":{"spans":{"type":"array","items":{"type":"object"}}}}}}}}}}}}},"responses":{"200":{"description":"Traces ingested (OTLP ExportTraceServiceResponse)","content":{"application/json":{"schema":{"type":"object","properties":{"partialSuccess":{"type":"object","properties":{"rejectedSpans":{"type":"integer","description":"Number of spans that failed ingestion"},"errorMessage":{"type":"string","description":"Error details when spans are rejected"}}}}}}}},"400":{"description":"Invalid OTLP payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/phoneConnections":{"get":{"tags":["phone-connections"],"summary":"Get phone connections","description":"Get list of phone connections with pagination and filtering. See [Phone Connections](https://docs.galtea.ai/concepts/product/phone-connection).","operationId":"getPhoneConnections","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by phone connection IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by phone connection names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by phone connection name (partial match)","required":false,"schema":{"type":"string"}},{"name":"phoneNumbers","in":"query","style":"form","explode":true,"description":"Filter by phone numbers (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"phoneNumber","in":"query","description":"Filter by phone number (partial match)","required":false,"schema":{"type":"string"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter phone connections created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter phone connections created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Phone connections retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PhoneConnection"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["phone-connections"],"summary":"Create phone connection","description":"Create a new phone connection. See [Phone Connections](https://docs.galtea.ai/concepts/product/phone-connection).","operationId":"createPhoneConnection","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneConnection"}}}},"responses":{"201":{"description":"Phone connection created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneConnection"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/phoneConnections/{id}":{"get":{"tags":["phone-connections"],"summary":"Get phone connection by ID","description":"Get a specific phone connection by ID. See [Phone Connections](https://docs.galtea.ai/concepts/product/phone-connection).","operationId":"getPhoneConnectionById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"PhoneConnection ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Phone connection retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneConnection"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Phone connection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["phone-connections"],"summary":"Update phone connection","description":"Update an existing phone connection. See [Phone Connections](https://docs.galtea.ai/concepts/product/phone-connection).","operationId":"updatePhoneConnection","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"PhoneConnection ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneConnection"}}}},"responses":{"200":{"description":"Phone connection updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneConnection"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Phone connection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["phone-connections"],"summary":"Delete phone connection","description":"Soft delete a phone connection. See [Phone Connections](https://docs.galtea.ai/concepts/product/phone-connection).","operationId":"deletePhoneConnection","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"PhoneConnection ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Phone connection deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Phone connection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/phoneConnections/batch":{"delete":{"tags":["phone-connections"],"summary":"Delete multiple phone connections","description":"Soft delete multiple phone connections by their IDs. See [Phone Connections](https://docs.galtea.ai/concepts/product/phone-connection).","operationId":"deletePhoneConnections","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of phone connection IDs to delete"}}}}}},"responses":{"204":{"description":"Phone connections deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webRtcConnections":{"get":{"tags":["web-rtc-connections"],"summary":"Get WebRTC connections","description":"Get list of WebRTC connections with pagination and filtering. See [WebRTC Connections](https://docs.galtea.ai/concepts/product/webrtc-connection).","operationId":"getWebRtcConnections","x-cli-name":"list","security":[{"bearerAuth":[]}],"parameters":[{"name":"ids","in":"query","style":"form","explode":true,"description":"Filter by WebRTC connection IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"productIds","in":"query","style":"form","explode":true,"description":"Filter by product IDs","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"names","in":"query","style":"form","explode":true,"description":"Filter by WebRTC connection names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"name","in":"query","description":"Filter by WebRTC connection name (partial match)","required":false,"schema":{"type":"string"}},{"name":"agentNames","in":"query","style":"form","explode":true,"description":"Filter by agent names (exact match, multiple)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"agentName","in":"query","description":"Filter by agent name (partial match)","required":false,"schema":{"type":"string"}},{"name":"sort","in":"query","style":"form","explode":true,"description":"Sort instructions (field and direction pairs)","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"Maximum number of results","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer"}},{"name":"fromCreatedAt","in":"query","description":"Filter WebRTC connections created at or after this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toCreatedAt","in":"query","description":"Filter WebRTC connections created at or before this timestamp (ISO 8601 format)","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"WebRTC connections retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebRtcConnection"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["web-rtc-connections"],"summary":"Create WebRTC connection","description":"Create a new WebRTC connection. See [WebRTC Connections](https://docs.galtea.ai/concepts/product/webrtc-connection).","operationId":"createWebRtcConnection","x-cli-name":"create","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebRtcConnection"}}}},"responses":{"201":{"description":"WebRTC connection created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebRtcConnection"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webRtcConnections/{id}":{"get":{"tags":["web-rtc-connections"],"summary":"Get WebRTC connection by ID","description":"Get a specific WebRTC connection by ID. See [WebRTC Connections](https://docs.galtea.ai/concepts/product/webrtc-connection).","operationId":"getWebRtcConnectionById","x-cli-name":"get","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"WebRtcConnection ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"WebRTC connection retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebRtcConnection"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"WebRTC connection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["web-rtc-connections"],"summary":"Update WebRTC connection","description":"Update an existing WebRTC connection. See [WebRTC Connections](https://docs.galtea.ai/concepts/product/webrtc-connection).","operationId":"updateWebRtcConnection","x-cli-name":"update","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"WebRtcConnection ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebRtcConnection"}}}},"responses":{"200":{"description":"WebRTC connection updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebRtcConnection"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"WebRTC connection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["web-rtc-connections"],"summary":"Delete WebRTC connection","description":"Soft delete a WebRTC connection. See [WebRTC Connections](https://docs.galtea.ai/concepts/product/webrtc-connection).","operationId":"deleteWebRtcConnection","x-cli-name":"delete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"WebRtcConnection ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"WebRTC connection deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"WebRTC connection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webRtcConnections/batch":{"delete":{"tags":["web-rtc-connections"],"summary":"Delete multiple WebRTC connections","description":"Soft delete multiple WebRTC connections by their IDs. See [WebRTC Connections](https://docs.galtea.ai/concepts/product/webrtc-connection).","operationId":"deleteWebRtcConnections","x-cli-name":"delete-batch","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","example":["id_1","id_2"],"items":{"type":"string"},"description":"Array of WebRTC connection IDs to delete"}}}}}},"responses":{"204":{"description":"WebRTC connections deleted successfully"},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/build-info":{"get":{"operationId":"buildInfo","tags":[],"summary":"Build info","description":"Deployed build metadata (version, commit, build date), so on-prem customers can compare their deployed version with the SaaS. Requires authentication; restricted to admins and organizations with an enterprise subscription.","security":[{"bearerAuth":[]}],"x-cli-name":"build-info","responses":{"200":{"description":"Deployed build metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildInfo"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/build-info/services":{"get":{"operationId":"buildInfoServices","tags":[],"summary":"Build info for every deployed service","description":"The API's own build metadata plus one entry per downstream Python service, so on-prem customers and support can see the full component inventory of a deployment at a glance. A downstream service being down never fails this call; it is reported with `status: unreachable` instead. Requires authentication; restricted to admins and organizations with an enterprise subscription, same rule as `GET /build-info`.","security":[{"bearerAuth":[]}],"x-cli-name":"build-info-services","responses":{"200":{"description":"Deployed build metadata for the API and every downstream service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildInfoServices"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/generate-config":{"post":{"operationId":"generateProductConfig","tags":["products"],"summary":"Generate product configuration using AI","description":"Uses AI to generate a refined product description and testable specifications from a product name and user description. Optionally accepts product specification files (documents, images, audio, video, code) to enrich the generation. See [Products](https://docs.galtea.ai/concepts/product).","security":[{"bearerAuth":[]}],"x-cli-name":"generate-config","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/GenerateProductConfigBody"}}}},"responses":{"200":{"description":"Product configuration generated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateProductConfigResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"AI generation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/{id}/regenerate-config":{"post":{"operationId":"regenerateProductConfig","tags":["products"],"summary":"Cross-check a document against an existing product's specifications","description":"Uploads one or more documents (PRD, spec, design doc, etc.), generates candidate specifications from them using the product's existing description as the generation base, and cross-checks each candidate against the product's CURRENT specifications. Returns classified suggestions — additions (`new`), updates to an existing specification (`updated`), and contradictions (`contradictory`). This endpoint persists NOTHING: applying a suggestion is a separate, explicit step via the specification endpoints.","security":[{"bearerAuth":[]}],"x-cli-name":"regenerate-config","parameters":[{"schema":{"type":"string","description":"Product ID","example":"prod_123"},"required":true,"description":"Product ID","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/RegenerateProductConfigBody"}}}},"responses":{"200":{"description":"Cross-check suggestions generated successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SpecificationSuggestion"}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"No permission to access this product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"AI generation or classification failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/testCases/{id}/replay-candidate-count":{"get":{"operationId":"getTestCaseReplayCandidateCount","tags":["test-cases"],"summary":"Count replay candidates per product for a test case revision","description":"For each requested product, returns how many historical evaluations in this test case's revision family would be replayed against this revision. A candidate is a distinct `(version, metric)` combination that any revision in the family was evaluated with (production sessions excluded) and whose version has not yet been run against this revision. Products with no candidates return `count: 0`. The revision must be the active head of its family, matching the replay call itself.","security":[{"bearerAuth":[]}],"x-cli-name":"get-replay-candidate-count","parameters":[{"schema":{"type":"string","description":"Test case revision ID","example":"testCase_123"},"required":true,"description":"Test case revision ID","name":"id","in":"path"},{"schema":{"type":"array","items":{"type":"string"},"description":"Repeated query param; one value per product."},"required":true,"description":"Repeated query param; one value per product.","style":"form","explode":true,"name":"productIds","in":"query"}],"responses":{"200":{"description":"Candidate counts per product","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReplayCandidateCount"}}}}},"400":{"description":"Invalid query or non-active revision target","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Test case or product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations":{"get":{"operationId":"getEvaluations","tags":["evaluations"],"summary":"Get evaluations","description":"Get list of evaluations with pagination and filtering. See [Evaluations](https://docs.galtea.ai/concepts/product/version/session/evaluation).","security":[{"bearerAuth":[]}],"x-cli-name":"list","parameters":[{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by evaluation IDs"},"required":false,"description":"Filter by evaluation IDs","style":"form","explode":true,"name":"ids","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by product IDs"},"required":false,"description":"Filter by product IDs","style":"form","explode":true,"name":"productIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by session IDs"},"required":false,"description":"Filter by session IDs","style":"form","explode":true,"name":"sessionIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by inference result IDs (for single-turn evaluations)"},"required":false,"description":"Filter by inference result IDs (for single-turn evaluations)","style":"form","explode":true,"name":"inferenceResultIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by metric IDs"},"required":false,"description":"Filter by metric IDs","style":"form","explode":true,"name":"metricIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by metric group IDs (matches all revisions of a metric)"},"required":false,"description":"Filter by metric group IDs (matches all revisions of a metric)","style":"form","explode":true,"name":"metricGroupIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by monitor IDs (returns only evaluations dispatched by the given monitors)"},"required":false,"description":"Filter by monitor IDs (returns only evaluations dispatched by the given monitors)","style":"form","explode":true,"name":"monitorIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by test case IDs"},"required":false,"description":"Filter by test case IDs","style":"form","explode":true,"name":"testCaseIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by test IDs (include only). Use an empty string (\"\") to select evaluations without a test"},"required":false,"description":"Filter by test IDs (include only). Use an empty string (\"\") to select evaluations without a test","style":"form","explode":true,"name":"testIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Omit evaluations linked to the specified test IDs. Use an empty string (\"\") to omit evaluations without a test"},"required":false,"description":"Omit evaluations linked to the specified test IDs. Use an empty string (\"\") to omit evaluations without a test","style":"form","explode":true,"name":"excludeTestIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by version IDs"},"required":false,"description":"Filter by version IDs","style":"form","explode":true,"name":"versionIds","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by specification IDs (returns evaluations whose metric is linked to any of the given specifications)"},"required":false,"description":"Filter by specification IDs (returns evaluations whose metric is linked to any of the given specifications)","style":"form","explode":true,"name":"specificationIds","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["PENDING","PENDING_HUMAN","SUCCESS","FAILED","SKIPPED","CANCELLED"]},"description":"Filter by evaluation statuses"},"required":false,"description":"Filter by evaluation statuses","style":"form","explode":true,"name":"statuses","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by evaluation types"},"required":false,"description":"Filter by evaluation types","style":"form","explode":true,"name":"evaluationTypes","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Filter by metric sources"},"required":false,"description":"Filter by metric sources","style":"form","explode":true,"name":"metricSources","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"description":"Sort instructions (field and direction pairs)"},"required":false,"description":"Sort instructions (field and direction pairs)","style":"form","explode":true,"name":"sort","in":"query"},{"schema":{"type":"boolean","description":"Filter evaluations that can be retried"},"required":false,"description":"Filter evaluations that can be retried","name":"canRetry","in":"query"},{"schema":{"type":"boolean","description":"Filter evaluations by whether their test case is augmented"},"required":false,"description":"Filter evaluations by whether their test case is augmented","name":"augmentedTestCase","in":"query"},{"schema":{"type":"boolean","description":"Filter evaluations by the joined `Session.isProduction` flag. Prefer this over the legacy `testIds`/`excludeTestIds` empty-string trick."},"required":false,"description":"Filter evaluations by the joined `Session.isProduction` flag. Prefer this over the legacy `testIds`/`excludeTestIds` empty-string trick.","name":"isProduction","in":"query"},{"schema":{"type":"string","description":"Filter by human evaluator user ID"},"required":false,"description":"Filter by human evaluator user ID","name":"humanEvaluatorId","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Filter evaluations created at or after this timestamp (ISO 8601 format)"},"required":false,"description":"Filter evaluations created at or after this timestamp (ISO 8601 format)","name":"fromCreatedAt","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Filter evaluations created at or before this timestamp (ISO 8601 format)"},"required":false,"description":"Filter evaluations created at or before this timestamp (ISO 8601 format)","name":"toCreatedAt","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":9007199254740991,"default":10000,"description":"Maximum number of results"},"required":false,"description":"Maximum number of results","name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0,"description":"Number of results to skip"},"required":false,"description":"Number of results to skip","name":"offset","in":"query"}],"responses":{"200":{"description":"Evaluations retrieved successfully","headers":{"Content-Range":{"schema":{"type":"string","description":"Pagination range as `evaluations <offset>-<upperBound>/<total>`."},"required":true,"description":"Pagination range as `evaluations <offset>-<upperBound>/<total>`."}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Evaluation"}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evaluations/fromTestCases":{"post":{"operationId":"evaluateFromTestCases","tags":["evaluations"],"summary":"Replay evaluations onto a new test case revision","description":"Re-runs the evaluations that any revision in `testCaseGroupId` was scored with against the new test case revision `newTestCaseId`, scoped to the given products. Because an evaluation is bound to a test case only through its session, fresh inference is generated for the new revision on each version that previously ran the family (production sessions excluded), then evaluated with the metrics that ran there. De-duplication skips a `(version, metric)` pair once it has a non-deleted evaluation against `newTestCaseId`, and skips a whole version once any non-deleted session exists for `newTestCaseId` — the session is created before this call returns, so a repeated or retried call re-dispatches nothing. This is still not a transactional guarantee for truly simultaneous calls. `newTestCaseId` must be the active head of its family.","security":[{"bearerAuth":[]}],"x-cli-name":"replay-from-test-cases","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFromTestCasesBody"}}}},"responses":{"202":{"description":"Replay job accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplayFromTestCasesResult"}}}},"400":{"description":"Invalid body, testCaseGroupId mismatch, or non-active revision target","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Test case or product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/comments":{"post":{"operationId":"createComment","tags":["comments"],"summary":"Create comment","description":"Adds a free-form annotation to an inference result, for error analysis outside the metric-bound evaluation flow. An inference result can hold many comments.","security":[{"bearerAuth":[]}],"x-cli-name":"create","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentRequest"}}}},"responses":{"201":{"description":"Comment created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/comments/tags":{"get":{"operationId":"listCommentTags","tags":["comments"],"summary":"List distinct comment labels","description":"Returns the sorted, distinct labels used on the comments of the requested products, lowercase and trimmed. Labels are product-scoped: this is the reuse list a reviewer picks from when annotating a turn, and the options of the session-list label filter. `productIds` is required; a product the caller cannot read yields 403.","security":[{"bearerAuth":[]}],"x-cli-name":"list-tags","parameters":[{"schema":{"type":"array","items":{"type":"string"},"description":"Products whose comment labels to list. At least one is required."},"required":true,"description":"Products whose comment labels to list. At least one is required.","style":"form","explode":true,"name":"productIds","in":"query"}],"responses":{"200":{"description":"Labels retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"example":["hallucination","tone"]}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/comments/{commentId}":{"delete":{"operationId":"deleteComment","tags":["comments"],"summary":"Delete comment","description":"Soft-deletes one comment. Only the author, or an ADMIN/OWNER, may delete it.","security":[{"bearerAuth":[]}],"x-cli-name":"delete","parameters":[{"schema":{"type":"string","description":"Comment ID","example":"comment_123"},"required":true,"description":"Comment ID","name":"commentId","in":"path"}],"responses":{"204":{"description":"Comment deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions/import":{"post":{"operationId":"importSessions","tags":["sessions"],"summary":"Import sessions from a Langfuse trace export","description":"Imports production traces from a Langfuse export. The content is handed to a background BullMQ job; the response is the `jobId` to poll on `GET /jobs/{jobId}/status`. Semantic validation (Langfuse shape, drop rules) happens in the job, so a syntactically valid upload is accepted with `202` and rejections surface as `failed` job state. Send EITHER `multipart/form-data` with a `file` OR `application/json` with a `text` string — exactly one. `isProduction` defaults to `true`. `versionId` is optional: when omitted, provide `productId` and the API reuses the product's latest version (creating a default first version if the product has none). One of `versionId` or `productId` is required.","security":[{"bearerAuth":[]}],"x-cli-name":"import","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceImportText"}},"multipart/form-data":{"schema":{"$ref":"#/components/schemas/TraceImportUpload"}}}},"responses":{"202":{"description":"Import accepted; poll the returned jobId for completion.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceImportResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Uploaded file exceeds the 25MB limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/specifications/generate-config":{"post":{"operationId":"generateSpecificationConfig","tags":["specifications"],"summary":"Generate specification configuration","description":"Uses AI to rewrite a rough or brief note into a properly written specification description and suggest its classification (type, test type, test variant) in a single request. Nothing is persisted — the caller decides which fields to apply and creates the specification explicitly. See [Specifications](https://docs.galtea.ai/concepts/product/specification).","security":[{"bearerAuth":[]}],"x-cli-name":"generate-config","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateSpecConfigBody"}}}},"responses":{"200":{"description":"Generated specification configuration returned successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecConfigResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"tags":[]}