Developer integrations
SingIt with the OpenAI Agents SDK
Python model calls with a capped SingIt API key.
Why
An agent loop can make many model calls on its own. With SingIt, the agent runs on a key with a daily cap, a per-request cap and an expiry, which your wallet signs. The key can use no more than that. When a cap is hit, the next call is refused and the run stops with an error you can handle. Calls made before that are not undone, and they were charged.
The limits apply to calls made with that key to SingIt. They do not limit what an agent spends anywhere else.
Model calls are paid from a prepaid SingIt balance the owner tops up in the SingIt app (Settings, API keys).
Install
pip install openai-agents
Make a key in the SingIt app (Settings, API keys) and keep it as SINGIT_API_KEY. Create an AsyncOpenAI client with base_url https://app.singitai.app/v1 and use OpenAIChatCompletionsModel, so the agent talks to SingIt over Chat Completions. Turn tracing off with set_tracing_disabled(True): the SDK's default tracing sends traces to OpenAI and uses OPENAI_API_KEY. Without that key it only logs a warning and skips the export, but with an OpenAI key set it would send your runs to OpenAI. Do not put the SingIt key into OPENAI_API_KEY.
There is no SingIt-specific Agents SDK package, and you do not need one for this route.
Code
import os
from openai import AsyncOpenAI
from agents import Agent, ModelSettings, OpenAIChatCompletionsModel, Runner, set_tracing_disabled
set_tracing_disabled(True) # default tracing sends runs to OpenAI and uses OPENAI_API_KEY
client = AsyncOpenAI(
base_url=os.environ.get("SINGIT_BASE_URL", "https://app.singitai.app/v1"),
api_key=os.environ["SINGIT_API_KEY"],
max_retries=0,
)
agent = Agent(
name="singit-agent",
instructions="Answer in one word.",
model=OpenAIChatCompletionsModel(model=os.environ.get("SINGIT_MODEL", "deepseek-v4.1-flash"), openai_client=client),
model_settings=ModelSettings(max_tokens=200),
)
print(Runner.run_sync(agent, "Reply with one word: pong").final_output)
Checked 2 November 2026 against a local test server that returns SingIt's error responses (langchain-openai 1.7.3, litellm 1.106.6, openai-agents 0.20.0). Not run against the live service.
What happens when the limit is exceeded
The call is refused before it is sent on, and that call is not charged. The SDK raises the usual openai exception, and the run ends. Catch it around Runner.run and decide what the agent does next.
| What happened | HTTP | error.code | What to do |
|---|---|---|---|
| The key's daily cap is used up (counting calls still running). Message: "This key's daily limit of 1 USDC is used up, counting requests still running. It starts again at 00:00 UTC, or raise it with a new key." (the number is the key's cap) | 429 | insufficient_quota | Wait for 00:00 UTC, or make a new key with a higher cap |
| One request would cost more than the per-request cap | 400 | over_request_limit | Lower max_tokens in ModelSettings, send less input (shorter history, fewer or smaller tools), pick a cheaper model, or make a key with a higher per-request cap |
| More than 60 requests a minute on one key | 429 | rate_limit_exceeded | Slow down and retry |
| Key wrong, revoked or expired | 401 | invalid_api_key | Make a new key |
| The SingIt balance is too low for the request (and automatic top-ups are off or refused) | 402 | balance_low | Top up in the SingIt app (Settings, API keys) |
| Payments are paused on SingIt's side | 503 | payments_paused | Try again later |
Create the client with max_retries=0 so a refused call is not retried. In a run that hits the cap partway, a tool that already ran stays done: the first call was charged, the next raises openai.RateLimitError, and Runner.run ends with it. Function tools need SingIt's proxy to be on (see above); production status is not verified.
Where the limit is enforced:
- Key caps (daily and per request) are checked by SingIt's server, not onchain, on Base and on Solana.
- On Base, the owner's allowance is an onchain limiter contract with its limits fixed in it. It limits what SingIt can buy from your wallet (for example balance top-ups and search), not each model call a key makes.
- On Solana, SingIt's server checks the daily limit, the per-purchase limit and the expiry. The chain enforces only the total you approved. The owner can stop new purchases from the app, including balance top-ups; revoking the delegation removes the onchain approval.
Revoking a key takes no wallet signature and is immediate.
Tools and real streaming work only when SingIt's server has its proxy on. This has not been checked live. A refusal always comes before a stream starts, as a normal HTTP error. A stream that breaks just ends, without an error event or a final completion marker; framework handling of a broken stream has not been checked. A started stream is charged for its cost or, if cost is unavailable, its reserved amount within the per-request cap.
A failed call may leave an automatic balance top-up as prepaid credit; the top-up is not undone.
Paying from your own wallet over x402 instead?
The Python x402 SDK offers a chat() call. Its limits are client-side and its daily counter is in memory, resetting when the process restarts. No Python adapter exists for this framework. See the python-x402 example.
Runnable code · Free-route and MCP snippets · SingIt API key documentation