Genuine native passthrough for Anthropic and OpenAI through the BlockRun
gateway — use an API key, or pay per call in USDC (x402) on Solana or Base
(vip.WithChain("solana")), with zero model substitution and zero response
reshaping.
Unlike a re-implemented client, the constructors here return the official
anthropic-sdk-go and openai-go client types. They only swap the transport (to add
x402 payment) and the base URL. The gateway returns the upstream provider's response
verbatim, so the official SDK parses the real signals:
- Claude:
claude-opus-5.5·claude-sonnet-5.5·claude-fable-5.1·claude-fable-5·claude-opus-5·claude-sonnet-5·claude-opus-4.8·claude-opus-4.7·claude-opus-4.5·claude-sonnet-4.6·claude-sonnet-4.5·claude-haiku-4.5. Opus 4.7 and up use adaptive thinking —anthropic.ThinkingConfigParamOfEnabled(N)is honored. - GPT: native
ID(chatcmpl-*),SystemFingerprint, honest token usage and JSON mode — routed to/v1/chat/completions.
A Claude / OpenAI relay detector sees a direct upstream call.
This is the Go counterpart of the Python blockrun-llm-vip package,
reusing the x402 signing and wallet loading from
blockrun-llm-go.
Register at user.blockrun.ai, create an API key, and add account credit.
export BLOCKRUN_API_KEY=brk_live_...client, err := vip.NewOpenAI() // no wallet required
// Explicit form, accepted by all constructors:
client, err = vip.NewOpenAI(vip.WithAPIKey("brk_live_..."))OpenAI/Anthropic native clients, Image/Speech/Music/Video, Voice/Phone,
Search/Exa and RealFace/Portrait share account authentication. Media submission
and polling use the same key; no x402 signing or wallet fallback occurs on
account errors. The root defaults to https://api.blockrun.ai and accepts
WithBaseURL, BLOCKRUN_API_KEY_URL (the main SDK's name for it) or
BLOCKRUN_API_BASE_URL (trailing /v1 is normalized). Credentials
are restricted to that origin and redirects are disabled. Account billing is
reported in the portal; wallet-owned asset lists still require a wallet.
WithAPIKey plus WithWalletKey is rejected. An explicit wallet key overrides
an environment API key. A value that is not an account key (vip.WithAPIKey("blockrun"),
the pre-v0.8 form) is still just the placeholder key sent upstream and keeps the
x402 wallet rail; a truncated brk_ secret is rejected where you set it. Any key
the main SDK accepts is accepted here, brk_test_ included. Without account credentials, explicit/saved wallet
choices and existing Base-only wallets are retained; otherwise Solana is
preferred. Chain/facilitator options do not select a billing chain in account mode.
The account rail rides on the released blockrun-llm-go v0.21.1, whose
constructors take a brk_ key wherever they take a wallet key — no replace
directive, so applications get it from a plain go get.
One caveat on the "verbatim" promise above: it is exact on the x402 wallet
rail. On the account rail the Anthropic responses carry gateway message ids
(msg_br_… rather than a native msg_…), and adaptive-thinking models return
real thinking signatures while some non-adaptive ones drop a thinking block
that the wallet rail keeps. OpenAI responses stay native on both rails
(chatcmpl-… ids, system_fingerprint, token-detail usage).
Video polling acceptance additionally requires the gateway's video signing-secret provisioning; local protocol tests cover that path, which is not a claim it is already live.
go get github.com/BlockRunAI/blockrun-llm-go-vipimport (
"github.com/anthropics/anthropic-sdk-go"
vip "github.com/BlockRunAI/blockrun-llm-go-vip"
)
// Claude — exactly the official anthropic-sdk-go API.
client, _ := vip.NewAnthropic() // wallet auto-loaded from ~/.blockrun/.session
msg, _ := client.Messages.New(ctx, anthropic.MessageNewParams{
Model: anthropic.Model("claude-opus-5"), // current flagship (adaptive thinking)
MaxTokens: 1024,
Thinking: anthropic.ThinkingConfigParamOfEnabled(1024),
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What is 23*47?")),
},
})
for _, b := range msg.Content {
if b.Type == "thinking" {
fmt.Println("signature:", b.Signature) // real Anthropic signature
}
}import (
vip "github.com/BlockRunAI/blockrun-llm-go-vip"
"github.com/openai/openai-go"
)
// GPT — exactly the official openai-go API.
gpt, _ := vip.NewOpenAI()
resp, _ := gpt.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
Model: openai.ChatModel("gpt-4o"),
Messages: []openai.ChatCompletionMessageParamUnion{openai.UserMessage("hi")},
})
fmt.Println(resp.SystemFingerprint, resp.Model) // genuine OpenAI directRunnable examples: examples/anthropic,
examples/openai, and examples/seedance.
You name the model; the gateway never substitutes it. Pass any current id verbatim:
- Claude:
claude-opus-5·claude-sonnet-5·claude-opus-4.8·claude-opus-4.7·claude-opus-4.5·claude-sonnet-4.6·claude-sonnet-4.5·claude-haiku-4.5. Opus 4.7 and up use adaptive thinking —anthropic.ThinkingConfigParamOfEnabled(N)is honored. - GPT:
gpt-6-astra·gpt-6.1-sol·gpt-6-sol·gpt-6-luna·gpt-5.6-sol·gpt-5.6-terra·gpt-5.6-luna(each 5.6 tier also as-pro) ·gpt-5.5·gpt-5.4·gpt-5.2·gpt-5.3-codex·gpt-4.1·gpt-4o·gpt-4o-mini, reasoningo3/o4-mini, and more. GPT‑5.x / o-series are reasoning models — leaveMaxTokens/Temperatureunset (the gateway normalizes them);gpt-4o/gpt-4o-miniare served OpenAI-direct.
The SDK also ships a 116-model catalog snapshot (chat, image, video, music, speech, and sound effects) so callers can build a picker without a network round trip:
for _, model := range vip.Models() {
fmt.Println(model.ID, model.Categories, model.ContextWindow, model.Pricing)
}
opus, ok := vip.FindModel("anthropic/claude-opus-5")Catalog ids are namespaced (anthropic/claude-opus-5), which is the form the media helpers
take. The gateway resolves either form on the chat routes, so model.ID works with
Messages.New / Chat.Completions.New too — but model.NativeID() gives the bare
provider id ("claude-opus-5") that matches the upstream SDK docs. FindModel accepts
either form. BillingMode ("paid", "free", or the media unit) identifies the free
NVIDIA tier; an unpriced media model is not free.
One gotcha: use the dotted ids above. Dashed variants are accepted only as a fixed alias
list, and a namespaced dashed id (anthropic/claude-sonnet-4-6) is rejected by
/v1/messages outright.
The snapshot (2026-10-20) covers Claude, GPT-6 and GPT-5.x, Gemini, DeepSeek, Grok, GLM,
Kimi, MiniMax, Qwen, MiMo, Mistral, the free tier, and media models. The gateway's
per-model available flag is a live health signal and is not part of the snapshot. Use https://blockrun.ai/api/v1/models when your application needs the
live catalog.
Generate short videos through ByteDance Seedance. The gateway runs generation
asynchronously, and the client mirrors that — Submit signs the x402 payment
authorization and returns immediately, then you Poll or Wait. USDC settles
on-chain only on the first poll that observes completed; failed or abandoned
jobs are never charged:
video, _ := vip.NewVideo()
// Async: submit returns a job handle without blocking.
job, _ := video.Submit(ctx, "a neon-lit cyberpunk street, slow dolly forward",
&vip.VideoGenerateOptions{Model: "bytedance/seedance-2.0-fast", DurationSeconds: 5})
fmt.Println(job.ID, job.Status) // e.g. "bytedance:video_…", "queued"
for !job.Done() {
time.Sleep(12 * time.Second)
video.Poll(ctx, job) // advances job.Status (see "How polling pays" below)
}
fmt.Println(job.Response.Data[0].URL) // permanent BlockRun-hosted MP4How polling pays: on Solana (vip.WithChain("solana")) each poll proves the
job is yours with a fresh ed25519 signature from your wallet over
blockrun-poll:v1:video:<job id>:<unix seconds> (headers x-poll-wallet,
x-poll-timestamp, x-poll-signature) — no payment is signed while the job is
pending. When the video is ready the gateway answers that poll with a 402
("status":"completed"); Poll signs exactly one payment from it and re-sends,
which settles the job and returns the video. If the gateway refuses the proof for
a job (e.g. one submitted before it bound payers, or a clock more than 300s off),
Poll logs it and falls back to x-payment polling for that job. Your system clock
must be within ±300s of real time. If the answer to that one paid poll is lost
or the gateway reports the settlement as in progress, Poll keeps polling (the
gateway settles a job at most once and hands back the video if it already did);
after 4 such polls in a row it returns a *vip.VideoPaymentInDoubtError carrying
the PollURL — resume by polling it with the same wallet, never by submitting
again. On Base every poll re-signs x402 as before. On every rail, a job that
failed upstream now ends as failed (never charged) instead of completed with
no video.
video.Wait(ctx, job) blocks until done, and video.Generate(ctx, prompt, opts) is
shorthand for Submit+Wait (one blocking call). Video is implemented natively in
this package; RealFace and Portrait reuse blockrun-llm-go's gateway clients. All
x402-paid on Base.
A specific, real person can appear consistently across clips: enroll once via
RealFace (one-time $0.01, ~1-min on-phone liveness for consent, no KYC), get a
ta_xxxx, and pass it as RealFaceAssetID on Seedance 2.0 / 2.0-fast. For an AI
character / mascot use Portrait instead (single enroll, no liveness).
portrait, _ := vip.NewPortrait()
asset, _ := portrait.Enroll(ctx, "Mascot", "https://example.com/character.jpg") // $0.01
job, _ := video.Generate(ctx, "the mascot waves in soft studio light",
&vip.VideoGenerateOptions{Model: "bytedance/seedance-2.0", RealFaceAssetID: asset.AssetID})RealFaceAssetID is mutually exclusive with ImageURL and only works on Seedance
2.0 / 2.0-fast. Constructors: vip.NewVideo, vip.NewRealFace, vip.NewPortrait.
Full real-person flow (RealFace state machine, on-phone liveness, error states): docs/real-person-flow.md.
img, _ := vip.NewImage()
out, _ := img.Generate(ctx, "a red fox in fresh snow, soft studio light",
&vip.ImageGenerateOptions{Model: "openai/gpt-image-1"})
fmt.Println(out.Data[0].URL)
// edit / multi-image fusion:
edited, _ := img.Edit(ctx, "make it night", []string{dataURI}, nil)Models: openai/gpt-image-1 · gpt-image-2 · gpt-image-2.5-flare · gpt-image-2.5-sunburst ·
google/nano-banana · nano-banana-2 · nano-banana-pro · xai/grok-imagine-image ·
grok-imagine-image-2.0 · grok-imagine-image-pro · bytedance/seedream-5-pro · zai/cogview-4. img.ListImageModels(ctx) lists them (free).
sp, _ := vip.NewSpeech()
speech, _ := sp.Generate(ctx, "Hello there.", &vip.SpeechGenerateOptions{Voice: "sarah"})
sfx, _ := sp.SoundEffect(ctx, "distant thunder over rain", nil)
mu, _ := vip.NewMusic()
instrumental := true
track, _ := mu.Generate(ctx, "dreamy lo-fi beat", &vip.MusicGenerateOptions{Instrumental: &instrumental})
fmt.Println(speech.Data[0].URL, sfx.Data[0].URL, track.Data[0].URL)sp.ListVoices(ctx) lists TTS voices (free). Music runs ~1-3 min and blocks until ready.
s, _ := vip.NewSearch()
r, _ := s.Search(ctx, "latest on x402 micropayments",
&vip.SearchOptions{Sources: []string{"x", "news"}, MaxResults: 15})
exa, _ := vip.NewExa()
hits, _ := exa.Search(ctx, "x402 protocol", map[string]any{"numResults": 5})
text, _ := exa.Contents(ctx, []string{"https://example.com"}, nil)
ans, _ := exa.Answer(ctx, "what is the x402 payment header?", nil)Lease a wallet-bound number, then place an AI-driven outbound call. Call returns a
call id; poll it with GetCallStatus for the transcript + recording.
phone, _ := vip.NewPhone()
num, _ := phone.BuyNumber(ctx, vip.BuyNumberOptions{Country: "US", AreaCode: "415"}) // $5, 30-day lease
voice, _ := vip.NewVoice()
call, _ := voice.Call(ctx, vip.CallOptions{
To: "+14155551234",
Task: "Ask if they're open Sunday, confirm hours, then thank them and end the call.",
MaxDuration: 3,
})
status, _ := voice.GetCallStatus(ctx, call.CallID)
fmt.Println(status)Phone also does Lookup / LookupFraud, ListNumbers, RenewNumber, ReleaseNumber.
vip.NewAnthropic(
vip.WithChain("solana"), // explicit wallet chain
vip.WithWalletKey("..."), // explicit key (Base hex, or bs58 on Solana)
vip.WithBaseURL("https://blockrun.ai/api"), // override the gateway
vip.WithSolanaRPCURL("https://..."), // override the Solana RPC (Solana only)
vip.WithFacilitator("payai"), // facilitator preference (Solana only; default "figment")
)All options apply to every constructor (NewOpenAI, NewImage, NewVideo, …).
Pass vip.WithChain("solana") to any constructor to pay USDC on Solana via
sol.blockrun.ai instead of Base — the drop-in stays identical:
claude, _ := vip.NewAnthropic(vip.WithChain("solana")) // bs58 key from ~/.blockrun/.solana-session
gpt, _ := vip.NewOpenAI(vip.WithChain("solana"))
img, _ := vip.NewImage(vip.WithChain("solana"))Payment is the x402 SVM "exact" scheme: the bs58 key signs a Solana
TransferChecked USDC transaction locally (ed25519), and BlockRun's facilitator
co-signs the fee and settles it gaslessly. Responses are still the upstream
provider's verbatim JSON. Runnable example: examples/solana.
Solana VIP clients send a facilitator preference (x-blockrun-facilitator: figment) plus the wallet's public address (x-payer-wallet) with each
request, so VIP traffic settles through the Figment facilitator while
other BlockRun clients keep using PayAI. Payment semantics are identical on
both rails (same x402 exact-scheme USDC transfer, gasless for the payer). Opt
out with vip.WithFacilitator("payai") or BLOCKRUN_FACILITATOR=payai — the
wire is then byte-identical to v0.6.x. Base chain is unaffected.
The private key is used only for local signing (EIP-712 on Base, SVM/ed25519 on Solana) and never leaves your machine.
Base resolution order:
WithWalletKey(...)optionBLOCKRUN_WALLET_KEYenvBASE_CHAIN_WALLET_KEYenv~/.blockrun/.session
Solana (WithChain("solana")) resolution order:
WithWalletKey(...)option (bs58)SOLANA_WALLET_KEYenv~/.*/solana-wallet.json(most recent)~/.blockrun/.solana-session
The gateway base URL can be overridden via BLOCKRUN_API_URL (Base) /
BLOCKRUN_SOLANA_API_URL (Solana); the Solana signing RPC via SOLANA_RPC_URL.
NewAnthropic / NewOpenAI build the official SDK client with two request options:
option.WithBaseURL(...)— point at the BlockRun gateway.option.WithMiddleware(...)— a transport middleware that performs the x402 handshake: the first request goes out unpaid; on a402thepayment-requiredrequirement is parsed, a USDC authorization is signed locally (EIP-712 on Base, the SVM "exact" scheme on Solana), and the original request is replayed verbatim with aPAYMENT-SIGNATUREheader. On200the upstream body is handed back untouched.
Because the middleware never reshapes the success response, the official SDK does all parsing — that is what makes the passthrough native.
Two failures recover automatically, both bounded, and both only on an explicit machine-readable signal from the gateway:
- Stale blockhash (
402) — the signed Solana transaction aged out. It is discarded, never replayed; the whole negotiation re-runs from a fresh quote and a fresh signature. - Verifier unavailable (
503 PAYMENT_VERIFICATION_UNAVAILABLE) — the gateway could not run its payer-risk screen and failed closed, so the payment was never judged. The request is retried honouring the server'sRetry-After(capped at 30s).
Every other response, including any other 503, is handed to the caller untouched. That
is deliberate: paid routes settle optimistically, in parallel with the upstream work, so
an unmarked 503 may arrive after the charge — retrying it would buy the same thing
twice. Recovery is limited to answers the gateway gives before anything is broadcast.
Covers, on Base or Solana (vip.WithChain("solana")):
- Anthropic + OpenAI native passthrough (
NewAnthropic,NewOpenAI). - Seedance video incl. RealFace real-person + Virtual Portrait (
NewVideo,NewRealFace,NewPortrait). - Image generate + edit (
NewImage). - Audio: ElevenLabs speech + sound effects (
NewSpeech), MiniMax music (NewMusic). - Search: Grok Live Search (
NewSearch) + Exa web search (NewExa). - Voice & Phone: AI phone calls (
NewVoice) + number provisioning (NewPhone).
Give BlockRun your wallet address to enable VIP, then pay per call from that wallet.
Contact: vicky@blockrun.ai