blnkd docs
Console ↗
DOCUMENTATION

TypeSafe Python SDK

Use typed Python requests with blnkd.

Use typesafe-sdk 0.7.1 with your blnkd API key. Tested with Noul, Choice, Score, 16-question batches, images, video, and async calls.

Install and connect

Use Python 3.10 or later.

bash
python -m pip install "typesafe-sdk==0.7.1"

Create a key in the console’s API Keys page, or follow the HTTP quickstart.

bash
export BLNKD_URL="https://api.blnkd.dev"
export BLNKD_API_KEY="your-blnkd-api-key"

Set base_url="https://api.blnkd.dev". Do not add /v1 — the SDK adds the path.

Ask typed questions

Save this as decision.py, then run python decision.py.

python
import os

from typesafe_sdk import Choice, Noul, RetryPolicy, Score, TypeSafeClient

with TypeSafeClient(
    base_url=os.environ["BLNKD_URL"],
    api_key=os.environ["BLNKD_API_KEY"],
    model="blink-1.0-experimental",
    timeout=280.0,
    retry=RetryPolicy(max_retries=0),
) as client:
    response = client.system_one(
        state={
            "report": "CSV export fails for three users. Dashboard and API work. Export through the API is a usable workaround.",
        },
        questions={
            "team": Choice(
                instructions="Which team should own this report?",
                criteria={
                    "engineering": "A product feature is failing",
                    "billing": "A payment or invoice issue",
                    "clarify": "Not enough context to identify an owner",
                },
            ),
            "multiple_users": Noul(
                instructions="Does the report explicitly say more than one user is affected?",
            ),
            "impact": Score(
                instructions="Rate the reported impact using the available evidence.",
                criteria=[
                    "Cosmetic issue; no task blocked",
                    "One task blocked with a usable workaround",
                    "Core task blocked without a workaround",
                    "Service unavailable to all users",
                ],
            ),
        },
    )

print(response.choices["team"].choice)
print(response.choices["team"].probabilities)
print(response.nouls["multiple_users"].noul)
print(response.scores["impact"].score)
print(response.scores["impact"].probabilities)
print(response.usage.input_tokens, response.usage.output_tokens)

The question name is the key you use to read its answer:

  • response.choices["team"] contains the selected label and the complete option distribution.
  • response.nouls["multiple_users"].noul is the probability assigned to true.
  • response.scores["impact"].score is a weighted mean of zero-based rubric levels. It is not a percentage.
  • response.usage contains the input and output token counts returned with the response.

The SDK exposes Score distribution keys as integers. The wire JSON uses strings. response.answers contains every answer if you prefer one combined mapping.

Use an async client

Use AsyncTypeSafeClient with await.

python
import asyncio
import os

from typesafe_sdk import AsyncTypeSafeClient, Choice, RetryPolicy

async def main():
    async with AsyncTypeSafeClient(
        base_url=os.environ["BLNKD_URL"],
        api_key=os.environ["BLNKD_API_KEY"],
        model="blink-1.0-experimental",
        timeout=280.0,
        retry=RetryPolicy(max_retries=0),
    ) as client:
        response = await client.system_one(
            state={"ticket": "My delivery is missing."},
            questions={
                "team": Choice(
                    instructions="Which team should handle this ticket?",
                    criteria={"shipping": "Delivery issues", "billing": "Payment issues"},
                ),
            },
        )
        print(response.choices["team"].choice)

asyncio.run(main())

Run one request at a time per account. Overlapping requests return 429.

Send an image

Pass an image through extra_body. This example uses package.jpg.

python
import base64
import os
from pathlib import Path

from typesafe_sdk import Choice, RetryPolicy, TypeSafeClient

# Use a local JPEG. Set the MIME type to match your file for PNG or WebP.
image = base64.b64encode(Path("package.jpg").read_bytes()).decode("ascii")

with TypeSafeClient(
    base_url=os.environ["BLNKD_URL"],
    api_key=os.environ["BLNKD_API_KEY"],
    model="blink-1.0-experimental",
    timeout=280.0,
    retry=RetryPolicy(max_retries=0),
) as client:
    response = client.system_one(
        state="Inspect visible packaging only. Do not infer damage to the contents.",
        questions={
            "condition": Choice(
                instructions="What condition is directly visible?",
                criteria={
                    "damaged": "Visible crushing, tearing, or puncture",
                    "intact": "Packaging appears intact",
                    "unclear": "Not enough visual evidence",
                },
            ),
        },
        extra_body={"images": [f"data:image/jpeg;base64,{image}"]},
    )

print(response.choices["condition"].choice)
print(response.choices["condition"].probabilities)

Send one PNG, JPEG, or WebP image. Use the correct MIME type and keep the entire JSON request below the API’s 16 MiB body limit. See Images for task design and Limits for request limits.

Send a video

Use extra_body for video too. Replace the image field in the example above:

python
video = base64.b64encode(Path("clip.mp4").read_bytes()).decode("ascii")

response = client.system_one(
    state="Inspect the attached clip.",
    questions={
        "outdoors": Noul(instructions="Is the scene outdoors?"),
    },
    extra_body={"videos": [f"data:video/mp4;base64,{video}"]},
)
print(response.nouls["outdoors"].noul)

Run this inside the client context. Import Noul from typesafe_sdk. Send one MP4 up to 10 MiB and 30 seconds. See Video inputs.

Handle errors

Catch TypeSafeAPIError and read error.status:

  • 401 — check the API key.
  • 402 — account quota reached.
  • 422 — check the input and model limits.
  • 429 — wait for the active request to finish.
  • 502 — the model request failed.

The examples disable automatic retries. A retry can count as another request. A client timeout does not mean the server stopped processing.

Supported calls

Use system_one() with model="blink-1.0-experimental". Responses are complete JSON objects. Streaming and model discovery are not supported.

See the SDK reference for client options.

Set up your coding agent

Copy this prompt into your agent.