Encrypted, Tor & I2P endpoints
The API is also published as a Tor onion service and an I2P eepsite. Same routes, same key; only the base URL and the proxy change.
Base URLs
Four addresses lead to the same API. Use the one that fits your network, with the same API key and the same requests.
| Network | Base URL | How you reach it |
|---|---|---|
| Clear web | https://api.shannon-ai.com/v1 | Direct, over HTTPS. |
| Encrypted mirror | https://api-encrypted.shannon-ai.com/v1 | Direct, over HTTPS. A second host name for the same API. |
| Tor (onion service) | http://shannonmd773o5vxz75byha5rkea7nzr3srotw46uwythq3pjl6y4cad.onion/v1 | Through a Tor client: a SOCKS5 proxy, by default at 127.0.0.1:9050. |
| I2P (eepsite) | http://acvnvkdea4xaczzjap7chysqqi4kkvp2eorfwkasindzmjpa47da.b32.i2p/v1 | Through an I2P router: an HTTP proxy, by default at 127.0.0.1:4444. |
- An OpenAI SDK takes the base URL as shown, with
/v1. An Anthropic SDK takes it without/v1. - To check an address, read the reply headers of
https://api.shannon-ai.com:Onion-Locationcarries the onion address andX-I2P-Locationthe I2P address. The onion address starts withshannon.
Which routes work
Every /v1 route answers on all four addresses:
POST /v1/chat/completionsPOST /v1/responsesPOST /v1/messagesPOST /v1/messages/count_tokensPOST /v1/tokenizeGET /v1/models
GET /v1/models needs no key, which makes it a quick test that your proxy reaches the API.
What is the same and what differs
| Item | Same? | Detail |
|---|---|---|
| Routes, request fields, replies, errors | Same | The same on every address. No route behaves differently by host name. |
| API key | Same | One key works on every address, as Authorization: Bearer or x-api-key. Cookies are never read on /v1. |
| Balance and limits | Same | The same balance and the same limit of 120 requests per minute. Both are counted per account, not per address. |
| Request size | Same | Up to 32 MiB per request body. |
| Scheme | Differs | https:// on the clear web and on the mirror. http:// on the .onion and .b32.i2p addresses, where the network itself encrypts the connection from end to end. |
| Proxy | Differs | None on the clear web. A SOCKS5 proxy for Tor, an HTTP proxy for I2P. The name must be resolved by the proxy, not by your machine. |
| Speed | Differs | Both networks add delay to every byte. I2P is the slower of the two. |
Balance and limits are described on their own page. Limits and balance
cURL through Tor
Run a Tor client on your machine. It offers a SOCKS5 proxy on 127.0.0.1:9050. --socks5-hostname hands the .onion name to that proxy.
# 1. Is the onion service reachable? No key needed.
curl --socks5-hostname 127.0.0.1:9050 http://shannonmd773o5vxz75byha5rkea7nzr3srotw46uwythq3pjl6y4cad.onion/v1/models
# 2. A streamed chat call. -N prints the stream as it arrives.
curl -N --socks5-hostname 127.0.0.1:9050 http://shannonmd773o5vxz75byha5rkea7nzr3srotw46uwythq3pjl6y4cad.onion/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "shannon-3",
"stream": true,
"messages": [{"role": "user", "content": "Hello over Tor"}]
}' cURL through I2P
Run an I2P router on your machine. It offers an HTTP proxy on 127.0.0.1:4444, which takes the .b32.i2p name as it is.
# 1. Is the eepsite reachable? No key needed.
curl --proxy http://127.0.0.1:4444 http://acvnvkdea4xaczzjap7chysqqi4kkvp2eorfwkasindzmjpa47da.b32.i2p/v1/models
# 2. A streamed chat call.
curl -N --proxy http://127.0.0.1:4444 http://acvnvkdea4xaczzjap7chysqqi4kkvp2eorfwkasindzmjpa47da.b32.i2p/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "shannon-3",
"stream": true,
"messages": [{"role": "user", "content": "Hello over I2P"}]
}' SDK base URL
An SDK needs two changes: the base URL of the network, and an HTTP client that goes through the proxy. In Python both official SDKs take an httpx client. For a SOCKS proxy install httpx[socks].
# pip install openai "httpx[socks]"
import httpx
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="http://shannonmd773o5vxz75byha5rkea7nzr3srotw46uwythq3pjl6y4cad.onion/v1",
http_client=httpx.Client(proxy="socks5h://127.0.0.1:9050", timeout=600),
)
stream = client.chat.completions.create(
model="shannon-3",
messages=[{"role": "user", "content": "Hello over Tor"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True) # pip install openai
import httpx
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="http://acvnvkdea4xaczzjap7chysqqi4kkvp2eorfwkasindzmjpa47da.b32.i2p/v1",
http_client=httpx.Client(proxy="http://127.0.0.1:4444", timeout=600),
)
stream = client.chat.completions.create(
model="shannon-3",
messages=[{"role": "user", "content": "Hello over I2P"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True) # pip install anthropic "httpx[socks]"
import anthropic
import httpx
client = anthropic.Anthropic(
api_key="YOUR_API_KEY",
base_url="http://shannonmd773o5vxz75byha5rkea7nzr3srotw46uwythq3pjl6y4cad.onion",
http_client=httpx.Client(proxy="socks5h://127.0.0.1:9050", timeout=600),
)
with client.messages.stream(
model="shannon-1.6-lite",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello over Tor"}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True) Streaming and keep-alive on slow links
Streaming works over both networks. While a stream is open and the model has nothing to send yet, the API sends a keep-alive, so the connection does not look dead to a proxy or to your client.
| Endpoint | Keep-alive on an open stream | Sent for |
|---|---|---|
/v1/chat/completions | A comment line (it starts with :) every 15 seconds. | All models |
/v1/messages | An event: ping, or a comment line, every 15 seconds. | All models |
/v1/responses | A comment line every 15 seconds. | Hosted open-weight models |
- Send
"stream": true. A streamed reply starts to arrive as soon as the model writes, and the keep-alive shows that the request is still being worked on. A non-streamed reply sends nothing until the whole answer is ready. - Give the client a long read timeout. The samples use 600 seconds. A timeout shorter than 15 seconds can end a stream between two keep-alives.
- Let your SSE reader skip comment lines and
pingevents. The SDKs do this already. - Do not resend a request the moment a connection drops. A request that reached the API runs to its end and is counted, also when the connection is gone.
- Test the path with
GET /v1/modelsfirst. It needs no key and returns a short JSON list.
Connection problems
| Symptom | Cause and fix |
|---|---|
The connection to 127.0.0.1:9050 or 127.0.0.1:4444 is refused | No Tor client or I2P router is running on your machine, or it listens on another port. Tor Browser offers its SOCKS proxy on port 9150. |
Could not resolve host for the .onion name | The client tried to resolve the name itself. Use --socks5-hostname in cURL and socks5h:// in a proxy URL, so the Tor client resolves it. |
| The I2P proxy answers with its own error page | The router has not found the address yet. A router needs a few minutes after it starts. Try again. |
401 with Missing authentication | The request arrived without a key. Send the same header as on the clear web. |
Every other error is the same as on the clear web. Error Handling
Your key without JavaScript
Shannon also has a website without JavaScript, reachable on the clear web, as an onion service and as an eepsite. Its /keys page shows your API key and lets you rotate it, so you can get a key without leaving Tor or I2P. encrypted.shannon-ai.com/keys
The addresses of that website on all three networks are listed here: Encrypted access