Getting Started

This guide walks you through making your first call to Shroud — first with the OpenAI-compatible HTTP path so you can paste-and-run, then with the Cocoon SDK if you need end-to-end encryption.

If you don't yet know which path you want, see Two paths in.

Prerequisites

Step 1: Get an API key

Obtain your API key through:

Keys are prefixed by environment:

Environment

Prefix

Example

Development

shroud_dev_

shroud_dev_abc123...

Staging

shroud_stage_

shroud_stage_abc123...

Production

shroud_prod_

shroud_prod_abc123...

Step 2: Authenticate

Include the key in every request via the Authorization header:

Authorization: Bearer shroud_prod_your_key_here

Base URLs

The examples below use shroud.us as the base host. Pick the environment that matches your API key:

Environment

Base URL

WebSocket base

Production

https://shroud.us

wss://shroud.us

Development

https://dev.shroud.us

wss://dev.shroud.us

Requests with a key for the wrong environment are rejected at the gateway.

Step 3: Make your first call

OpenAI-compatible chat completions

The fastest path. The gateway is OpenAI-compatible at /v1/chat/completions, so any OpenAI client works after a single base_url change. The gateway terminates TLS itself and forwards your prompt into a TEE — this trades end-to-end confidentiality for drop-in compatibility. For end-to-end-encrypted inference jump to Step 4: use the Cocoon SDK.

Pick the language tab that matches your stack. Each tab walks through the same three steps: set the API key in your environment, install or invoke the client, and run a hello-world chat completion.

export SHROUD_API_KEY=shroud_prod_... curl -X POST https://shroud.us/v1/chat/completions \ -H "Authorization: Bearer $SHROUD_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "Qwen/Qwen3-32B", "messages": [ {"role": "user", "content": "Hello!"} ], "max_tokens": 256, "stream": true }'

Shroud does not publish a Python SDK. Use the upstream openai-python client and override base_url.

export SHROUD_API_KEY=shroud_prod_... pip install openai
import os from openai import OpenAI client = OpenAI( api_key=os.environ["SHROUD_API_KEY"], base_url="https://shroud.us/v1", ) stream = client.chat.completions.create( model="Qwen/Qwen3-32B", messages=[{"role": "user", "content": "Hello!"}], max_tokens=256, stream=True, ) for chunk in stream: delta = chunk.choices[0].delta if delta.content: print(delta.content, end="", flush=True)
export SHROUD_API_KEY=shroud_prod_... npm install openai
import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.SHROUD_API_KEY, baseURL: "https://shroud.us/v1", }); const stream = await client.chat.completions.create({ model: "Qwen/Qwen3-32B", messages: [{ role: "user", content: "Hello!" }], max_tokens: 256, stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); }
export SHROUD_API_KEY=shroud_prod_... go get github.com/sashabaranov/go-openai
package main import ( "context" "fmt" "io" "os" openai "github.com/sashabaranov/go-openai" ) func main() { cfg := openai.DefaultConfig(os.Getenv("SHROUD_API_KEY")) cfg.BaseURL = "https://shroud.us/v1" client := openai.NewClientWithConfig(cfg) stream, err := client.CreateChatCompletionStream(context.Background(), openai.ChatCompletionRequest{ Model: "Qwen/Qwen3-32B", Messages: []openai.ChatCompletionMessage{ {Role: "user", Content: "Hello!"}, }, MaxTokens: 256, Stream: true, }) if err != nil { panic(err) } defer stream.Close() for { resp, err := stream.Recv() if err == io.EOF { break } if err != nil { panic(err) } fmt.Print(resp.Choices[0].Delta.Content) } }

See OpenAI-compatible API for the full request and response reference.

MCP for AI agents

The MCP endpoint speaks JSON-RPC 2.0 and requires an initialize handshake before any other call. Start by discovering capabilities — this endpoint is public and needs no authentication:

curl https://shroud.us/.well-known/mcp

Open a session by sending initialize. The response header Mcp-Session-Id must be echoed back on every subsequent request:

curl -i -X POST https://shroud.us/mcp \ -H "Authorization: Bearer shroud_prod_..." \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": { "name": "my-agent", "version": "0.1.0" } } }'

Then invoke a tool using the session ID from that response:

curl -X POST https://shroud.us/mcp \ -H "Authorization: Bearer shroud_prod_..." \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "Mcp-Session-Id: <session-id-from-initialize>" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "midnight_getBlock", "arguments": { "height": 100 } } }'

JSON-RPC tools

For non-MCP integrations the same tool surface is exposed at /rpc:

curl -X POST https://shroud.us/rpc \ -H "Authorization: Bearer shroud_prod_..." \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools.call", "params": { "tool": "midnight_getBlock", "params": {"height": 100} } }'

Direct Midnight RPC proxy

Query the Midnight node directly using whitelisted Substrate RPC methods:

curl -X POST https://shroud.us/v1/midnight/rpc \ -H "Authorization: Bearer shroud_prod_..." \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"chain_getFinalizedHead","params":[]}'

Step 4: Use the Cocoon SDK for confidential inference

The OpenAI-compatible HTTP path lets the gateway see your prompts in clear. For confidential inference where the platform operator must not see plaintext, use one of the official Cocoon SDKs. The SDK opens a WebSocket to wss://shroud.us/v1/cocoon/stream, performs an ECDH key exchange against a TEE-attested public key, and AES-256-GCM-encrypts every message end-to-end.

Go

go get github.com/AlphaTONCapital/shroud-sdk-go
package main import ( "context" "fmt" "github.com/AlphaTONCapital/shroud-sdk-go/cocoon" ) func main() { client := cocoon.NewClient("wss://shroud.us", cocoon.WithAPIKey("shroud_prod_..."), ) stream, err := client.Inference(context.Background(), &cocoon.InferenceRequest{ Model: "Qwen/Qwen3-32B", Messages: []cocoon.Message{{Role: "user", Content: "Hello!"}}, Stream: true, }) if err != nil { panic(err) } defer stream.Close() for { chunk, ok := stream.Next() if !ok { break } fmt.Print(chunk.Content) } if err := stream.Err(); err != nil { panic(err) } }

TypeScript

npm install @alphatoncapital/shroud-sdk
import { CocoonClient } from '@alphatoncapital/shroud-sdk'; const client = new CocoonClient('wss://shroud.us', { apiKey: 'shroud_prod_...', }); const stream = await client.inference({ model: 'Qwen/Qwen3-32B', messages: [{ role: 'user', content: 'Hello!' }], stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.content); }

See Confidential inference for the architecture and Go SDK/TypeScript SDK for the full references.

Troubleshooting

401 Unauthorized

  • Verify your API key format: shroud_{env}_{32 hex chars}.

  • Check the environment prefix matches the deployment (dev_, stage_, prod_).

  • Ensure the Authorization header uses the Bearer prefix.

  • Check that the key hasn't expired or been revoked in the dashboard.

429 Too Many Requests

  • Check your plan's RPS limit (Free plan = 2 requests/second).

  • Add delays between requests or upgrade your plan.

  • If the response includes "code": "cu_limit_exceeded", you've hit the CU budget.

Connection refused / timeout

  • Verify the base URL is correct and reachable.

  • For the Cocoon SDK use wss:// (not https://) as the base URL.

  • Check that firewall rules allow outbound WebSocket connections.

See Error reference for the complete error code list.

Next steps

Last modified: 08 May 2026