Skip to content
DecisionNodeDecisionNdedocs
  • Guides
  • API reference
  • Examples
  • Playground

start here

  • QuickstartGet startedGet an API key, send one request with three questions, and branch your code on the typed answers. Plain HTTPS, no SDK to install.
  • POST /v1/decideAPI referenceAnswer typed questions about a state and optional images. One request, one buffered JSON response, one answer per question.
  • QuestionsConceptsQuestions say what to decide. Each one has a type that fixes the shape of its answer: a choice from your options, a score on your scale, a…
  • ConfidenceConceptsProbabilities are calibrated per question type, so a threshold means what it says.
  • ImagesConceptsSend images and text in the same request. The model reads printed and handwritten text, amounts, dates, objects and layout, and answers…
  • Batch jobsPatternsSend up to 10,000 requests in one file and collect the answers later, at half the live price.
  • Pricing and billingYou pay for input tokens only. Output is free because the model generates no text.
↑↓ moveopen7 suggestions
Get API keyGet API key
DecisionNodeDecisionNde

Get started

  • Introduction
  • Quickstart
  • Playground
  • Console and keys
  • With coding agents
  • Examples

Concepts

  • State
  • Questions
  • Choice
  • Score
  • Truth
  • Number
  • Images
  • Confidence
  • Determinism

Models

  • DecisionNode-1.0
  • DecisionNode-1.0 Flash
  • Limits
  • Versions
  • Dedicated capacity

Patterns

  • Confidence-gated routing
  • Fan-out
  • Guardrails
  • Control loops
  • Batch jobs

API reference

  • Overview
  • POST/v1/decide
  • GET/v1/models
  • Errors
  • Safety check
  • Rate limits

Sessions API

  • Sessions overview
  • POSTOpen a session
  • WSStream frames
  • DELEnd a session

Batch API

  • The batch object
  • POSTCreate a batch
  • POSTAdd requests
  • POSTFinalize a batch
  • GETRetrieve a batch
  • GETGet batch results
  • POSTCancel a batch
  • GETList batches

Pricing and billing

  • Pricing and billing

Policies

  • Responsible use
  • Data and privacy

Migrate

  • Coming from a Jev-shaped API
  • Benchmarks
  • Pricing
  • Playground
Get API key
  • Guides
  • API reference
  • Examples
  • Playground

Get started

  • Introduction
  • Quickstart
  • Playground
  • Console and keys
  • With coding agents
  • Examples

Concepts

  • State
  • Questions
  • Choice
  • Score
  • Truth
  • Number
  • Images
  • Confidence
  • Determinism

Models

  • DecisionNode-1.0
  • DecisionNode-1.0 Flash
  • Limits
  • Versions
  • Dedicated capacity

Patterns

  • Confidence-gated routing
  • Fan-out
  • Guardrails
  • Control loops
  • Batch jobs

API reference

  • Overview
  • POST/v1/decide
  • GET/v1/models
  • Errors
  • Safety check
  • Rate limits

Sessions API

  • Sessions overview
  • POSTOpen a session
  • WSStream frames
  • DELEnd a session

Batch API

  • The batch object
  • POSTCreate a batch
  • POSTAdd requests
  • POSTFinalize a batch
  • GETRetrieve a batch
  • GETGet batch results
  • POSTCancel a batch
  • GETList batches

Pricing and billing

  • Pricing and billing

Policies

  • Responsible use
  • Data and privacy

Migrate

  • Coming from a Jev-shaped API
  1. docs
  2. /
  3. Sessions API

Open a session

Send the fixed part of your request once: model, instructions, state, questions and window. Get back a session id, the WebSocket to stream frames to, and when the session expires.

on this page6 sections
  1. Authentication
  2. Request body
  3. Response
  4. Errors
  5. Limits
  6. Notes
POSThttps://api.decisionnode.com/v1/sessions
# session.json holds the body below
curl https://api.decisionnode.com/v1/sessions \
  -H "Authorization: Bearer $DECISIONNODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @session.json

Reads the instructions, the state and the questions once, keeps them loaded for the life of the session, and bills them once. Every frame you stream afterwards is answered on them.

Authentication#

Authorizationheaderrequired
Bearer dn_live_..., the same key as every call. A session belongs to the key that opened it: other keys, even in the same workspace, get 404 for it (close code 4404 on the stream).
Content-Typeheaderrequired
application/json.

Request body#

session.json
{
  "model": "decisionnode-latest",
  "instructions": "You are the mission supervisor of a survey drone.",
  "state": {
    "mission": "Survey the north field in parallel lines, 40 m altitude",
    "geofence": "Stay inside the field boundary and below 120 m",
    "rules": "Return home when battery is under 30% at the far end of a line"
  },
  "questions": {
    "mode": {
      "type": "choice",
      "instructions": "Which flight mode now?",
      "criteria": {
        "continue": "keep flying the survey pattern",
        "hold": "hover in place until conditions change",
        "return": "fly back to the home point",
        "land": "land at the nearest safe spot now"
      }
    },
    "abort": {
      "type": "truth",
      "instructions": "Should the mission be aborted now?"
    }
  },
  "window": 8
}
modelstringdefault "decisionnode-latest"
decisionnode-latest or decisionnode-flash-latest, or a pinned version such as decisionnode-1.0, as on /v1/decide. Every frame of the session is answered by this model. Any other name is a 400.
instructionsstring | object | array
Who the model decides as, for every frame of the session. Read once, with the state.
statestring | object | arraydefault ""
The static context: a mission brief, a rulebook, a map legend. Read once when the session opens and kept loaded for its life.
questionsobjectrequired
The questions every frame is answered on, in the same shape as on /v1/decide: choice, score, truth or number. Their keys are the names a frame's questions list uses.
windowintegerdefault 8
How many frames each frame is answered with, the frame itself included, beside the fixed part: 1 to 64. 1 answers each frame on the fixed part and that frame alone. When the recent frames together pass the session's window_tokens, the oldest leave first. Outside 1 to 64 is a 422.
ttl_secondsintegerdefault 300
How long the session lives from the moment it opens, 1 to 3,600; outside that is a 422. Activity does not extend it.

Response#

200 OK with the session. Connect to stream_url next; see Stream frames.

200 OK
{
  "session_id": "ses_3f9a1c07b2e84d5f6a0c9e12",
  "model": "decisionnode-1.0",
  "stream_url": "wss://api.decisionnode.com/v1/sessions/ses_3f9a1c07b2e84d5f6a0c9e12/stream",
  "window": 8,
  "ttl_seconds": 300,
  "expires_at": "2026-10-06T09:35:00Z",
  "limits": {
    "max_frame_tokens": 1535,
    "max_frame_images": 1,
    "window_tokens": 1536,
    "idle_timeout_seconds": 120
  },
  "questions": ["mode", "abort"],
  "prefix_tokens": 52,
  "usage": { "input_tokens": 164, "output_tokens": 0 },
  "answers": {
    "mode": {
      "type": "choice",
      "choice": "continue",
      "confidence": 0.84,
      "probabilities": {
        "continue": 0.88,
        "hold": 0.06,
        "land": 0.01,
        "return": 0.05
      }
    },
    "abort": { "type": "truth", "truth": 0.03 }
  },
  "safety": {
    "checked": true,
    "harm": 0.0018,
    "self_harm": 0.0007,
    "flagged": []
  }
}
session_idstring
The session's id: ses_ and 24 hex digits, such as ses_3f9a1c07b2e84d5f6a0c9e12. Treat it as opaque. Use it to end the session.
modelstring
The pinned version that answers every frame, for example decisionnode-1.0.
stream_urlstring
The WebSocket to connect to: wss://api.decisionnode.com/v1/sessions/{id}/stream with this session's id.
windowinteger
The window in force.
ttl_secondsinteger
The lifetime in force.
expires_atstring
When it ends unless you end it first: ttl_seconds after this call, ISO 8601 in UTC.
limitsobject
This session's own limits.
max_frame_tokensinteger
Tokens of text or JSON per frame in this session: at most 4,096, and less when window_tokens is smaller, since a frame never holds more than the window's room.
max_frame_imagesinteger
Images per frame, 1.
window_tokensinteger
Tokens the recent frames may hold together. Past it, the oldest frames leave the window first.
idle_timeout_secondsinteger
How long the socket may go without a frame, 120. Past it the socket closes with 4408; pings do not count as frames.
questionsstring[]
The question keys, in order: the names a frame's questions list uses.
prefix_tokensinteger
The tokens of the instructions and the state.
usageobject
The fixed part with every question, billed once now: input_tokens, and output_tokens, always 0.
answersobject
Every question answered on the fixed part alone, before any frame, in the shapes of /v1/decide.
safetyobject
What the safety check found for the fixed part, in the same shape as on every reply.
  1. Authentication
  2. Request body
  3. Response
  4. Errors
  5. Limits
  6. Notes
request
# session.json holds the body belowcurl https://api.decisionnode.com/v1/sessions \  -H "Authorization: Bearer $DECISIONNODE_API_KEY" \  -H "Content-Type: application/json" \  -d @session.json

Errors#

  • 400

    Type
    api_usage_error
    When
    An unknown model or question type, a field the body does not take, a question over its limits, images in the body (images go in frames), or a model whose sessions.enabled is false
    What to do
    Fix the body; the message names the problem
  • 400

    Type
    max_tokens_exceeded
    When
    The fixed part, with room for the window and the longest question, does not fit: keep it within sessions.max_prefix_tokens
    What to do
    Trim the state or move detail into frames; x-decisionnode-error has the count
  • 401

    Type
    authentication_error
    When
    The key is missing, unknown or revoked
    What to do
    Check the Authorization header
  • 402

    Type
    insufficient_credit
    When
    Your prepaid balance is empty
    What to do
    Add credit, then open the session
  • 403

    Type
    refusal_error
    When
    The safety check refused the fixed part; the body names the category
    What to do
    Do not retry; change what the session asks. See Safety check
  • 408

    Type
    request_timeout_error
    When
    The body stopped arriving for 20 seconds, or took over 300
    What to do
    Retry on a working connection, with backoff
  • 413

    Type
    request_too_large_error
    When
    The body is over 64 MB
    What to do
    Trim the state; send detail that changes in frames
  • 422

    Type
    a detail list
    When
    A field is missing or has the wrong type, window outside 1 to 64, ttl_seconds outside 1 to 3,600, a number grid that cannot be built, or the body is not JSON
    What to do
    Fix the fields listed in detail
  • 429

    Type
    rate_limit_error
    When
    Your key already holds sessions.max_per_key open sessions
    What to do
    End a session you no longer use, then open again
  • 429

    Type
    rate_limit_error
    When
    Over your key's request rate
    What to do
    Wait Retry-After seconds, then retry
  • 500

    Type
    api_error
    When
    A fault on our side
    What to do
    Retry with backoff and jitter; it is always safe
  • 529

    Type
    overloaded_error
    When
    No capacity right now, or no room for another session
    What to do
    Wait Retry-After seconds, then retry with backoff
Errors this endpoint returns
StatusTypeWhenWhat to do
400api_usage_errorAn unknown model or question type, a field the body does not take, a question over its limits, images in the body (images go in frames), or a model whose sessions.enabled is falseFix the body; the message names the problem
400max_tokens_exceededThe fixed part, with room for the window and the longest question, does not fit: keep it within sessions.max_prefix_tokensTrim the state or move detail into frames; x-decisionnode-error has the count
401authentication_errorThe key is missing, unknown or revokedCheck the Authorization header
402insufficient_creditYour prepaid balance is emptyAdd credit, then open the session
403refusal_errorThe safety check refused the fixed part; the body names the categoryDo not retry; change what the session asks. See Safety check
408request_timeout_errorThe body stopped arriving for 20 seconds, or took over 300Retry on a working connection, with backoff
413request_too_large_errorThe body is over 64 MBTrim the state; send detail that changes in frames
422a detail listA field is missing or has the wrong type, window outside 1 to 64, ttl_seconds outside 1 to 3,600, a number grid that cannot be built, or the body is not JSONFix the fields listed in detail
429rate_limit_errorYour key already holds sessions.max_per_key open sessionsEnd a session you no longer use, then open again
429rate_limit_errorOver your key's request rateWait Retry-After seconds, then retry
500api_errorA fault on our sideRetry with backoff and jitter; it is always safe
529overloaded_errorNo capacity right now, or no room for another sessionWait Retry-After seconds, then retry with backoff

Every error body is {"detail": {"error_type": "...", "message": "..."}}, or a list of fields for a 422. Retry 408, 429, 529 and any 5xx, waiting at least what Retry-After says when it is set; fix the request for the other 4xx. All the bodies are on Errors.

Limits#

  • Fixed part

    Value
    At most sessions.max_prefix_tokens at /v1/models, with room left for the window and the longest question
  • window

    Value
    1 to 64, 8 by default
  • ttl_seconds

    Value
    1 to 3,600, 300 by default
  • Open sessions per key

    Value
    sessions.max_per_key at /v1/models
Limits that apply to this call
LimitValue
Fixed partAt most sessions.max_prefix_tokens at /v1/models, with room left for the window and the longest question
window1 to 64, 8 by default
ttl_seconds1 to 3,600, 300 by default
Open sessions per keysessions.max_per_key at /v1/models

Notes#

  • The session counts toward your open sessions from this call until it ends, whether or not a socket is connected. End sessions you do not use.
  • Connect soon after this call: expires_at counts from here, not from the connect. Once a socket is connected, it closes after idle_timeout_seconds (120 seconds) without a frame.
  • Opening the same body twice opens two sessions, each billed for its fixed part. If an open call times out and you open again, a session the first call may have opened gets no socket and ends at its expires_at; until then it counts toward your open sessions.
  • The safety check reads the fixed part once, here; every frame is checked again when it arrives.
previousSessionsnextStream frames

DecisionNode is built and run by Bynn Intelligence, Inc.

  • Home
  • Playground
  • Examples
  • Console
  • Responsible use
  • Terms
  • Acceptable use
  • Privacy
  • Data processing
  • Defence addendum
  • Cookies