Use the OpenAI client
Point the stock openai Python package at VORQ through the sealing transport, synchronously or in background mode.
The coordinator never accepts a plaintext prompt. To use the stock openai package, route it
through vorq.sealing_http_client(), a drop-in http_client that seals each Responses request
in your process. It is also the SDK's synchronous path: no asyncio needed.
Install
pip install vorq openaiSet VORQ_WALLET_KEY as in the Quickstart.
Configure the client
from openai import OpenAI
import vorq
client = OpenAI(
base_url="https://api.vorq.co/v1",
api_key="unused", # any non-empty string; the wallet authenticates
http_client=vorq.sealing_http_client(),
)sealing_http_client()talks tohttps://api.vorq.coand signs withVORQ_WALLET_KEY.- To post a bid that rests until a provider takes it, pass
verifier=vorq.Verifier("https://api.vorq.co")as well: such an order is sealed to the coordinator's escrow key, which the client verifies first.
Create a response and wait for it
resp = client.responses.create(
model="moonshotai/kimi-k3",
input="Say hello.",
extra_body={"vorq": {"sla": "batch"}},
)
print(resp.output_text)Without background, the call blocks until the job settles, for at most the job's sla
window. If the job hasn't settled by then, the call raises openai.BadRequestError.
The vorq block carries the order terms the Responses schema has no field for: sla,
rate_in, rate_out and an optional provider id.
sladefaults to"1h"on this path.- With no rates, the order takes the market: the first provider the coordinator ranks, at its own ask. See Bids and matching.
Create a response in the background
Use background=True whenever the wait might outlive your connection, for example on the
"24h" window:
import time
resp = client.responses.create(
model="moonshotai/kimi-k3",
input="Summarize the attached notes in three bullet points.",
background=True,
extra_body={"vorq": {"sla": "batch"}},
)
job_id = resp.id # the response id is the job id; persist it
while resp.status in {"queued", "in_progress"}:
time.sleep(30)
resp = client.responses.retrieve(job_id)
print(resp.status, resp.output_text)In either mode, a job that didn't deliver comes back as a Response with status failed or
cancelled and an error object whose code is the cause (provider_fail, reclaim,
cancelled or expired). It is not raised as an exception.
client.responses.cancel(job_id) cancels a job no provider has claimed yet. Once a provider has
claimed it, the cancel raises openai.ConflictError.
Media and batches
- A media job comes back as
image_generation_calloutput items, one per frame, with the frame's base64 inresult. Video uses the same item type. - Batches are created with the native
client.batches.submit(); the stock client can then retrieve, list and cancel them and read their output files. See Submit a batch.
What doesn't work
- Calling the transport inside a running event loop. It raises, and
openaireports anAPIConnectionError. In async code, usevorq.Client. stream=True, requestmetadata, and every route other than Responses and a short list of read-only routes. These are refused with a400before anything is sent.- Automatic retries of a failed create. Retry it yourself if you want one.
The full rules, including the forwarded routes and the error mapping, are in the OpenAI transport reference.