curl --request POST \
--url https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject \
--header 'Content-Type: application/json' \
--data '
{
"seed_ids": [
"3c90c3cc-0d44-4b50-8888-8dd25736052a"
],
"triage_note": "<string>"
}
'import requests
url = "https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject"
payload = {
"seed_ids": ["3c90c3cc-0d44-4b50-8888-8dd25736052a"],
"triage_note": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({seed_ids: ['3c90c3cc-0d44-4b50-8888-8dd25736052a'], triage_note: '<string>'})
};
fetch('https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'seed_ids' => [
'3c90c3cc-0d44-4b50-8888-8dd25736052a'
],
'triage_note' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject"
payload := strings.NewReader("{\n \"seed_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"triage_note\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject")
.header("Content-Type", "application/json")
.body("{\n \"seed_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"triage_note\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"seed_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"triage_note\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"succeeded": [
{
"seed_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"slug": "<string>",
"state_changed_at": "2023-11-07T05:31:56Z",
"promoted_project_id": "<string>",
"triaged_by": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"triage_note": "<string>",
"dramatic_premise": "<string>",
"dramatic_situation": "<string>",
"central_tension": {},
"human_tension_grounding": {},
"protagonist_shape": {},
"stakes": {},
"tone": "<string>",
"pack_affinity": [
{}
],
"risk_flags": [],
"provenance": {},
"quality_scores": {},
"durability_class": "<string>",
"freshness_ts": "2023-11-07T05:31:56Z",
"stale_after": "2023-11-07T05:31:56Z",
"resonance_score": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}
],
"failed": [
{
"seed_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"error": "<string>",
"detail": "<string>"
}
]
}{
"error": "Forbidden",
"code": "forbidden",
"request_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"message": "Your API key does not have the required scope.",
"doc_url": "https://docs.kitefrost.ai/errors/forbidden"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}{
"error": "Rate limit exceeded",
"code": "rate_limited",
"request_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"message": "You have exceeded the rate limit for your plan.",
"doc_url": "https://docs.kitefrost.ai/errors/rate_limited"
}{
"error": "Internal server error",
"code": "internal_error",
"request_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"message": "An unexpected error occurred.",
"doc_url": "https://docs.kitefrost.ai/errors/internal_error"
}Bulk reject seeds (transition to REJECTED)
Bulk reject: for each supplied seed UUID, transition TRIAGED → REJECTED via SeedLifecycleStore.transition. REJECTED is a terminal state that also writes the dead-seed registry (C-SSD §2.2) so the same premise will not regenerate. Per-item failures are isolated.
curl --request POST \
--url https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject \
--header 'Content-Type: application/json' \
--data '
{
"seed_ids": [
"3c90c3cc-0d44-4b50-8888-8dd25736052a"
],
"triage_note": "<string>"
}
'import requests
url = "https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject"
payload = {
"seed_ids": ["3c90c3cc-0d44-4b50-8888-8dd25736052a"],
"triage_note": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({seed_ids: ['3c90c3cc-0d44-4b50-8888-8dd25736052a'], triage_note: '<string>'})
};
fetch('https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'seed_ids' => [
'3c90c3cc-0d44-4b50-8888-8dd25736052a'
],
'triage_note' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject"
payload := strings.NewReader("{\n \"seed_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"triage_note\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject")
.header("Content-Type", "application/json")
.body("{\n \"seed_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"triage_note\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kitefrost.ai/v1/projects/{project_id}/seeds/batch/reject")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"seed_ids\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"triage_note\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"succeeded": [
{
"seed_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"slug": "<string>",
"state_changed_at": "2023-11-07T05:31:56Z",
"promoted_project_id": "<string>",
"triaged_by": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"triage_note": "<string>",
"dramatic_premise": "<string>",
"dramatic_situation": "<string>",
"central_tension": {},
"human_tension_grounding": {},
"protagonist_shape": {},
"stakes": {},
"tone": "<string>",
"pack_affinity": [
{}
],
"risk_flags": [],
"provenance": {},
"quality_scores": {},
"durability_class": "<string>",
"freshness_ts": "2023-11-07T05:31:56Z",
"stale_after": "2023-11-07T05:31:56Z",
"resonance_score": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}
],
"failed": [
{
"seed_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"error": "<string>",
"detail": "<string>"
}
]
}{
"error": "Forbidden",
"code": "forbidden",
"request_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"message": "Your API key does not have the required scope.",
"doc_url": "https://docs.kitefrost.ai/errors/forbidden"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}{
"error": "Rate limit exceeded",
"code": "rate_limited",
"request_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"message": "You have exceeded the rate limit for your plan.",
"doc_url": "https://docs.kitefrost.ai/errors/rate_limited"
}{
"error": "Internal server error",
"code": "internal_error",
"request_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"message": "An unexpected error occurred.",
"doc_url": "https://docs.kitefrost.ai/errors/internal_error"
}Body
Body of POST .../seeds/batch/{validate,reject}.
A flat list of seed UUIDs plus an optional shared note that gets
stamped on every successful transition. The size cap is enforced
inside the handler (explicit 400) rather than via Pydantic
max_length so the failure mode is a clean 400 Bad Request
with a stable schema, not the framework's default 422.
Response
Batch processed (per-id verdicts in body)
Response shape for both batch endpoints.
succeeded carries the per-id verdicts that landed; failed
carries per-id reasons (not_found, cross_tenant,
invalid_transition, error). The HTTP status code is always
200 once the request has cleared validation - per-item failure
does NOT abort the batch (per-item error isolation per design §
Batch).