API REFERENCE
Create a decision
Provide a state, instructions, and candidate choices. Receive probabilities for the next decision.
/v1/decisionsJSONThe hosted endpoint and request example follow the official API cookbook. View source
Free API: no key
We provide a free API with limited capacity for evaluation and small requests. The example needs no key. Retry later on HTTP 429 and avoid concurrent batch workloads.
https://api.valen-team.workers.dev/v1/decisions
The free endpoint supports valen-preview-0923, valen-2b, valen-4b, and valen-0-8b, selected through model. Each request accepts one question named q0: predicate, choice, or score. Supply 2–8 choices for choice, or 2–8 ordered levels (label, description) for score, with temperature: 1.0. Text is limited to 4000 characters, instructions to 1000, and each choice description to 300. Keep images under 3 MB and request bodies under 4,500,000 bytes.
Python/cURL examples include the Origin header required by the free endpoint. The website demo and Valen API Hugging Face Space can call it directly; browser calls from other websites are not enabled. Origin is not an access credential.
Higher quotas: request a key by email
For batch workloads or higher quotas, email liuziyu77@sjtu.edu.cn with your use case, expected volume, and input types. Quotas are subject to confirmation by the service operator.
Once approved, change the example URL to the official endpoint and send your own key through Authorization: Bearer. Never put keys in frontend code.
import os
url = "https://llm-proxy.openxxlab.com/v1/decisions"
headers = {"Authorization": "Bearer " + os.environ["VALEN_API_KEY"]}
Request body
APPLICATION/JSONChoose valen-preview-0923, valen-2b, valen-4b, or valen-0-8b. Examples default to valen-2b.
Text context, or a message list containing text and image inputs.
questionsobject[]REQUEST
The free endpoint accepts one question named q0 per request.
A name to identify the question.
Supports predicate (Yes/No), choice, and score.
Describe what the model should decide.
choicesobject[]
Each candidate includes a value and a description.
{"value": "cat", "description": "A cat"}levelsobject[]
For score: 2–8 ordered levels, each with label and description. The returned score is the probability-weighted average of level indices starting at 0.
{"label": "High", "description": "Strong purchase intent"}The cookbook example uses 1.0. Consult the hosted service documentation for its parameter contract.
Read the response
Read the question results from answers. Keep the question identifiers and candidate choices for the next step in your application.
response.json()["answers"][0]Predicate returns probability (the probability the condition is true); choice returns choice and probabilities; score returns score and level probabilities (label, numeric index value, probability). Score is weighted over level indices starting at 0: five levels span 0–4. Optional confidence is separate. Confidence is a separate field, not the maximum choice probability. Answers match questions by position and echo their name. Select a model with the request model field; the response includes a model_id identifier.
Multimodal inputs
Represent an image as a JPEG data URL in a message containing input_text and input_image, then pass the message list as input.
Understand the data format and local interfaceVideo input: decisions from a frame
The homepage video example extracts the middle frame of an MP4, then sends its JPEG data URL as input_image. This is not a video upload; hosted input_video support has not been verified. A single frame cannot establish motion or event order.
python -m pip install requests "Pillow>=10" av==16.1.0
Place assets/cookbook/momos.mp4 from the official repository in the working directory and use the free endpoint without a key. Only one JPEG is uploaded; frame extraction happens locally.
import base64
import io
import av
import requests
# Extract the middle frame, following the official cookbook.
video_path = "momos.mp4"
with av.open(video_path) as video:
frame_count = sum(1 for _ in video.decode(video=0))
if frame_count == 0:
raise ValueError("The video has no decodable frames")
with av.open(video_path) as video:
for index, frame in enumerate(video.decode(video=0)):
if index == frame_count // 2:
image = frame.to_image()
break
buffer = io.BytesIO()
image.save(buffer, format="JPEG", quality=95)
image_url = "data:image/jpeg;base64," + base64.b64encode(
buffer.getvalue()
).decode("ascii")
response = requests.post(
"https://api.valen-team.workers.dev/v1/decisions",
headers={"Origin": "https://valen-team.github.io"},
json={
"model": "valen-2b",
"input": [{
"role": "user",
"content": [
{"type": "input_text", "text": "Answer using only the visible image."},
{"type": "input_image", "image_url": image_url},
],
}],
"questions": [{
"name": "q0",
"type": "choice",
"instructions": "What is the color of the sauce in the foil container on the left?",
"choices": [
{"value": "brown", "description": "Brown"},
{"value": "white", "description": "White"},
{"value": "red", "description": "Red"},
{"value": "orange", "description": "Orange"},
],
}],
"temperature": 1.0,
},
timeout=120,
)
response.raise_for_status()
answer = response.json()["answers"][0]
print(answer["choice"], answer["confidence"])
for entry in answer["probabilities"]:
print(entry["value"], entry["probability"])