Pengganti langsung
Berfungsi dengan SDK OpenAI dan Anthropic. Cukup ganti base URL.
Semua bahasa setara. Pilih bahasa yang ingin Anda gunakan untuk menjelajah.
The uncensored AI API: Shannon models with no refusals and no filters, served from our own GPUs. OpenAI- and Anthropic-compatible — drop in the SDK you already use, one key, streaming, tool calling and reasoning on every endpoint.
api-encrypted.shannon-ai.com shannon…4cad.onion acvnvkde….b32.i2p Tor & I2P endpoints → 9 Shannon tiers and 12 hosted open-weight models behind one endpoint, with streaming and tool calling on every id. Usage is billed against your token quota, valued at $5 per million quota tokens. Model ids are stable — pin them in production; GET /v1/models returns this same table.
| Model | Input | Structured output | In / out per 1M | |
|---|---|---|---|---|
3BIT-REAPDeepSeek · 1.6T MoE · 49B active | Text in | JSON schema | $1.95 / $3.90 | More → |
3BIT-REAPZ.ai · 744B MoE · 40B active | Text in | JSON schema | $0.73 / $2.34 | More → |
3BIT-REAPMoonshot AI · 2.8T MoE · 104B active | Text + image in | JSON schema | $3.83 / $19.12 | More → |
3BIT-REAPNVIDIA · 550B hybrid Mamba-Attention MoE · 55B active | Text in | JSON schema | $0.75 / $3.30 | More → |
3BIT-REAPMiniMax · 428B MoE · 23B active · sparse attention | Text + image in | JSON schema | $0.50 / $2.00 | More → |
W4A16-AUTOROUND-REAPDeepSeek · 284B MoE · 13B active | Text in | JSON schema | $0.50 / $2.00 | More → |
W4A16-AUTOROUND-REAPMoonshot AI · 1T MoE · 32B active | Text + image in | JSON schema | $0.78 / $3.67 | More → |
W4A16-AUTOROUND-REAPPoolside · 118B MoE · 8B active | Text in | No structured output | $0.50 / $2.00 | More → |
W4A16-AUTOROUND-REAPThinking Machines · 975B MoE · 41B active | Text + image in | JSON object | $1.42 / $6.07 | More → |
W8A16Xiaomi · 1.02T MoE · 42B active · 8-bit | Text in | JSON schema | $0.50 / $2.00 | More → |
W8A16Xiaomi · 8-bit multimodal · W8A16 | Text + image in | JSON schema | $0.50 / $2.00 | More → |
W8A16Tencent · 295B MoE · 21B active · 8-bit | Text in | JSON schema | $0.50 / $2.00 | More → |
| Model | Context | Input | Structured output | Price / 1M tokens |
|---|---|---|---|---|
shannon-1.6-lite | 192K | Text + image in | JSON schema | $3.90 |
shannon-1.6-pro | 192K | Text + image in | JSON schema | $7.80 |
shannon-2-lite | 192K | Text + image in | JSON schema | $3.90 |
shannon-2-pro | 192K | Text + image in | JSON schema | $5.85 |
shannon-3 | 192K | Text + image in | JSON schema | $3.35 |
shannon-3-pro | 192K | Text + image in | JSON schema | $3.35 |
shannon-3.1 | 192K | Text + image in | JSON schema | $3.35 |
shannon-3.1-pro | 192K | Text + image in | JSON schema | $3.35 |
shannon-coder-1 | 128K | Text in | JSON schema | $8.00 |
Streaming responses include exact token usage in the final chunk. You are billed for the tokens you send and the reasoning and answer you receive — never for the pipeline's own rendering passes.
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.shannon-ai.com/v1"
)
response = client.chat.completions.create(
model="shannon-3",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello, Shannon!"}
],
max_tokens=1024
)
print(response.choices[0].message.content) import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'YOUR_API_KEY',
baseURL: 'https://api.shannon-ai.com/v1'
});
const response = await client.chat.completions.create({
model: 'shannon-3',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'Hello, Shannon!' }
],
max_tokens: 1024
});
console.log(response.choices[0].message.content); package main
import (
"context"
"fmt"
openai "github.com/sashabaranov/go-openai"
)
func main() {
config := openai.DefaultConfig("YOUR_API_KEY")
config.BaseURL = "https://api.shannon-ai.com/v1"
client := openai.NewClientWithConfig(config)
resp, err := client.CreateChatCompletion(
context.Background(),
openai.ChatCompletionRequest{
Model: "shannon-3",
Messages: []openai.ChatCompletionMessage{
{Role: "system", Content: "You are a helpful assistant."},
{Role: "user", Content: "Hello, Shannon!"},
},
MaxTokens: 1024,
},
)
if err != nil {
panic(err)
}
fmt.Println(resp.Choices[0].Message.Content)
} curl -X POST "https://api.shannon-ai.com/v1/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "shannon-3",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello, Shannon!"}
],
"max_tokens": 1024
}' {
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1234567890,
"model": "Shannon 1.6 Lite",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! I'm Shannon, your AI assistant. How can I help you today?"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 25,
"completion_tokens": 18,
"total_tokens": 43
}
} Try every model and endpoint in the browser with your own key — streaming output, request inspector, and generated code you can paste straight into your app.
Chat with any model, three endpoint dialects, tool calls, live latency and cost.
Everything the chat product can do, exposed over the wire.
Berfungsi dengan SDK OpenAI dan Anthropic. Cukup ganti base URL.
Tentukan alat, biarkan Shannon memanggilnya. Mendukung mode auto, paksa, dan none.
Pencarian web real‑time dengan sitasi sumber. Tersedia otomatis.
Mode JSON dan penegakan JSON Schema untuk ekstraksi data yang andal.
Loop eksekusi fungsi otomatis. Hingga 10 iterasi per permintaan.
Server‑sent events untuk streaming token secara real‑time.
Point your existing OpenAI or Anthropic SDK at Shannon and keep the same code. Every endpoint speaks the format you already use.
https://api.shannon-ai.com/v1/chat/completions Gunakan Chat Completions API dengan function calling dan streaming.
https://api.shannon-ai.com/v1/messages Format Claude Messages dengan tools dan header anthropic-version.
Otorisasi: Bearer <kunci-anda> Atau gunakan X-API-Key dengan anthropic-version untuk panggilan gaya Claude.
Public docs - Key required to call Streaming, function calling, output terstruktur, dan pencarian web.
One key works everywhere. OpenAI-style requests use a Bearer header; Anthropic-style requests use x-api-key.
Authorization: Bearer YOUR_API_KEY
x-api-key: YOUR_API_KEY anthropic-version: 2023-06-01
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.
| Network | Base URL |
|---|---|
| Clear web | https://api.shannon-ai.com/v1 |
| Clear web (TLS, encrypted mirror) | https://api-encrypted.shannon-ai.com/v1 |
| Tor (onion service) | http://shannonmd773o5vxz75byha5rkea7nzr3srotw46uwythq3pjl6y4cad.onion/v1 |
| I2P (eepsite) | http://acvnvkdea4xaczzjap7chysqqi4kkvp2eorfwkasindzmjpa47da.b32.i2p/v1 |
cURL through Tor
cURL · Tor curl --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-lite", "stream": true, "messages": [{"role": "user", "content": "Hello over Tor"}]}' cURL through I2P
cURL · I2P curl --proxy http://127.0.0.1:4444 http://acvnvkdea4xaczzjap7chysqqi4kkvp2eorfwkasindzmjpa47da.b32.i2p/v1/models \
-H "Authorization: Bearer YOUR_API_KEY"
SDK base URL
Python · openai 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),
) Cookies are never accepted on /v1, so the API key is the only credential. Streaming works over both networks; keep-alive frames are sent every few seconds.
from openai import OpenAI
import json
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.shannon-ai.com/v1"
)
# Define available tools/functions
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name, e.g., 'Tokyo'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
}
}
]
response = client.chat.completions.create(
model="shannon-3",
messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
tools=tools,
tool_choice="auto"
)
# Check if model wants to call a function
if response.choices[0].message.tool_calls:
tool_call = response.choices[0].message.tool_calls[0]
print(f"Function: {tool_call.function.name}")
print(f"Arguments: {tool_call.function.arguments}") import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'YOUR_API_KEY',
baseURL: 'https://api.shannon-ai.com/v1'
});
const tools = [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Get current weather for a location',
parameters: {
type: 'object',
properties: {
location: { type: 'string', description: "City name" },
unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }
},
required: ['location']
}
}
}
];
const response = await client.chat.completions.create({
model: 'shannon-3',
messages: [{ role: 'user', content: "What's the weather in Tokyo?" }],
tools,
tool_choice: 'auto'
});
if (response.choices[0].message.tool_calls) {
const toolCall = response.choices[0].message.tool_calls[0];
console.log('Function:', toolCall.function.name);
console.log('Arguments:', toolCall.function.arguments);
} "auto" | Model decides whether to call a function (default) |
"none" | Disable function calling for this request |
{"type": "function", "function": {"name": "..."}} | Force a specific function call |
{
"id": "chatcmpl-xyz",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\": \"Tokyo\", \"unit\": \"celsius\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
]
} from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.shannon-ai.com/v1"
)
# Force JSON output with schema
response = client.chat.completions.create(
model="shannon-3",
messages=[
{"role": "user", "content": "Extract: John Doe, 30 years old, engineer"}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "person_info",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"occupation": {"type": "string"}
},
"required": ["name", "age", "occupation"]
}
}
}
)
import json
data = json.loads(response.choices[0].message.content)
print(data) # {"name": "John Doe", "age": 30, "occupation": "engineer"} import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'YOUR_API_KEY',
baseURL: 'https://api.shannon-ai.com/v1'
});
const response = await client.chat.completions.create({
model: 'shannon-3',
messages: [
{ role: 'user', content: 'Extract: John Doe, 30 years old, engineer' }
],
response_format: {
type: 'json_schema',
json_schema: {
name: 'person_info',
schema: {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'integer' },
occupation: { type: 'string' }
},
required: ['name', 'age', 'occupation']
}
}
}
});
const data = JSON.parse(response.choices[0].message.content);
console.log(data); // { name: "John Doe", age: 30, occupation: "engineer" } {"type": "json_object"} | Force valid JSON output (no specific schema) |
{"type": "json_schema", "json_schema": {...}} | Force output matching your exact schema |
Server-sent events, OpenAI chunk format. Thinking models stream reasoning_content deltas before the answer; the final chunk carries exact usage.
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.shannon-ai.com/v1"
)
# Enable streaming for real-time responses
# Thinking models stream reasoning_content first, then content
stream = client.chat.completions.create(
model="GLM-5.2-3BIT-REAP",
messages=[
{"role": "user", "content": "Write a short poem about AI"}
],
stream=True
)
for chunk in stream:
delta = chunk.choices[0].delta
if getattr(delta, "reasoning_content", None):
print(delta.reasoning_content, end="", flush=True) # thinking stream
if delta.content:
print(delta.content, end="", flush=True) import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'YOUR_API_KEY',
baseURL: 'https://api.shannon-ai.com/v1'
});
// Enable streaming for real-time responses
// Thinking models stream reasoning_content first, then content
const stream = await client.chat.completions.create({
model: 'GLM-5.2-3BIT-REAP',
messages: [
{ role: 'user', content: 'Write a short poem about AI' }
],
stream: true
});
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta;
if (delta?.reasoning_content) process.stdout.write(delta.reasoning_content); // thinking stream
if (delta?.content) process.stdout.write(delta.content);
} POST /v1/responses — the OpenAI Responses dialect: instructions, input items, function_call / function_call_output for tool loops, reasoning summaries as output items. Same models, same key.
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")
response = client.responses.create(
model="shannon-3",
instructions="You are a concise assistant.",
input="Summarize the three-way handshake in two sentences.",
reasoning={"effort": "low"},
)
print(response.output_text)
# Tool loop: function_call items come back in response.output; answer them
# with function_call_output items on the next call. import OpenAI from 'openai';
const client = new OpenAI({ apiKey: 'YOUR_API_KEY', baseURL: 'https://api.shannon-ai.com/v1' });
const response = await client.responses.create({
model: 'shannon-3',
instructions: 'You are a concise assistant.',
input: 'Summarize the three-way handshake in two sentences.',
reasoning: { effort: 'low' },
});
console.log(response.output_text); Streaming emits response.created, reasoning_summary_text.delta, output_text.delta, function_call_arguments.delta and response.completed; a failed generation ends with response.failed. Non-streaming is the default.
Every thinking model streams its trace as reasoning_content deltas (or a thinking block) before the answer, and finish_reason: length tells you the answer hit max_tokens. The depth knob — reasoning_effort on /v1/chat/completions (off, low, medium, high), reasoning.effort on /v1/responses, thinking.budget_tokens on /v1/messages — is read by the hosted open-weight models; the Shannon tiers accept it and choose their own depth. GET /v1/models reports reasoning_effort per model.
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")
# reasoning_effort: off | low | medium | high. Read by the hosted open-weight
# models, where it sets how long the solve pass thinks. Shannon tiers accept the
# field and pick their own depth -- GET /v1/models reports which is which.
stream = client.chat.completions.create(
model="GLM-5.2-3BIT-REAP",
reasoning_effort="medium",
stream=True,
messages=[{"role": "user", "content": "Is 221 prime?"}],
)
for chunk in stream:
delta = chunk.choices[0].delta
if getattr(delta, "reasoning_content", None):
print(delta.reasoning_content, end="", flush=True) # thinking
if delta.content:
print(delta.content, end="", flush=True) # answer import OpenAI from 'openai';
const client = new OpenAI({ apiKey: 'YOUR_API_KEY', baseURL: 'https://api.shannon-ai.com/v1' });
// On /v1/messages the same knob is thinking: { type: 'enabled', budget_tokens }.
const stream = await client.chat.completions.create({
model: 'GLM-5.2-3BIT-REAP',
reasoning_effort: 'medium', // read by the hosted open-weight models
stream: true,
messages: [{ role: 'user', content: 'Is 221 prime?' }],
});
for await (const chunk of stream) {
const d = chunk.choices[0]?.delta ?? {};
if (d.reasoning_content) process.stdout.write(d.reasoning_content);
if (d.content) process.stdout.write(d.content);
} Set web_search: true and the model grounds its answer with live results.
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.shannon-ai.com/v1"
)
# Web search is automatically available!
# Shannon will use it when needed for current information
response = client.chat.completions.create(
model="shannon-3",
messages=[
{"role": "user", "content": "What are the latest AI news today?"}
],
# Optionally, explicitly define web_search tool
tools=[{
"type": "function",
"function": {
"name": "web_search",
"description": "Search the web for current information",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"]
}
}
}]
)
print(response.choices[0].message.content)
# Response includes sources and citations import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'YOUR_API_KEY',
baseURL: 'https://api.shannon-ai.com/v1'
});
// Web search is automatically available!
// Shannon will use it when needed for current information
const response = await client.chat.completions.create({
model: 'shannon-3',
messages: [
{ role: 'user', content: 'What are the latest AI news today?' }
],
// Optionally, explicitly define web_search tool
tools: [{
type: 'function',
function: {
name: 'web_search',
description: 'Search the web for current information',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' }
},
required: ['query']
}
}
}]
});
console.log(response.choices[0].message.content);
// Response includes sources and citations Drop-in for the Anthropic SDK — point it at our base URL and keep your Messages code.
https://api.shannon-ai.com/v1/messages import anthropic
client = anthropic.Anthropic(
api_key="YOUR_API_KEY",
base_url="https://api.shannon-ai.com"
)
response = client.messages.create(
model="shannon-3",
max_tokens=1024,
messages=[
{"role": "user", "content": "Hello, Shannon!"}
],
# Tool use (Anthropic format)
tools=[{
"name": "web_search",
"description": "Search the web",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
}]
)
print(response.content[0].text) import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
apiKey: 'YOUR_API_KEY',
baseURL: 'https://api.shannon-ai.com'
});
const response = await client.messages.create({
model: 'shannon-3',
max_tokens: 1024,
messages: [
{ role: 'user', content: 'Hello, Shannon!' }
],
// Tool use (Anthropic format)
tools: [{
name: 'web_search',
description: 'Search the web',
input_schema: {
type: 'object',
properties: {
query: { type: 'string' }
},
required: ['query']
}
}]
});
console.log(response.content[0].text); Use Shannon as the model behind Claude Code, Codex CLI and other agent CLIs.
Anthropic's official CLI coding agent. Point it at Shannon to use as your AI backend for reading, editing, and running code directly in your terminal.
ANTHROPIC_BASE_URL=https://api.shannon-ai.com ANTHROPIC_API_KEY=sk-YOUR_KEY claude OpenAI's open-source coding agent. Uses the Responses API for multi-turn tool use, file editing, and shell commands — all routed through Shannon.
OPENAI_BASE_URL=https://api.shannon-ai.com/v1 OPENAI_API_KEY=sk-YOUR_KEY codex # Install Claude Code (requires Node.js 18+) npm install -g @anthropic-ai/claude-code # Connect to Shannon AI as backend export ANTHROPIC_BASE_URL=https://api.shannon-ai.com export ANTHROPIC_API_KEY=sk-YOUR_API_KEY # Launch Claude Code in bare mode (no Anthropic account needed) claude # Or run a one-shot command claude -p "Explain this codebase" # Claude Code will use Shannon's Anthropic-compatible API # for all AI operations: reading files, editing code, # running tests, and multi-turn tool use.
# Alternative: set env vars permanently in your shell profile # ~/.bashrc or ~/.zshrc export ANTHROPIC_BASE_URL=https://api.shannon-ai.com export ANTHROPIC_API_KEY=sk-YOUR_API_KEY # Then just run: claude # Supported features through Shannon: # - Multi-turn conversations with full context # - File reading and editing (tool use) # - Shell command execution # - Streaming responses # - All Claude Code slash commands (/compact, /clear, etc.)
# Install Codex CLI npm install -g @openai/codex # Connect to Shannon AI as backend export OPENAI_BASE_URL=https://api.shannon-ai.com/v1 export OPENAI_API_KEY=sk-YOUR_API_KEY # Launch Codex codex # Or run a one-shot command codex "fix the bug in main.py" # Codex uses the Responses API (POST /v1/responses) # Shannon handles tool calls including: # - Reading and writing files # - Running shell commands # - Multi-turn function calling
# Alternative: set env vars permanently # ~/.bashrc or ~/.zshrc export OPENAI_BASE_URL=https://api.shannon-ai.com/v1 export OPENAI_API_KEY=sk-YOUR_API_KEY # Then just run: codex # Supported features through Shannon: # - Responses API with full tool use # - Function calling (file read/write, shell exec) # - Streaming with real-time output # - Multi-turn conversations # - All Codex approval modes (suggest, auto-edit, full-auto)
Any OpenAI or Anthropic SDK works out of the box.
Official OpenAI Python SDK - works with Shannon
pip install openai Documentation → Official OpenAI Node.js SDK - works with Shannon
npm install openai Documentation → Community Go client for OpenAI-compatible APIs
go get github.com/sashabaranov/go-openai Documentation → Community Ruby client for OpenAI-compatible APIs
gem install ruby-openai Documentation → Community PHP client for OpenAI-compatible APIs
composer require openai-php/client Documentation → Async Rust client for OpenAI-compatible APIs
cargo add async-openai Documentation → Official Anthropic Python SDK - works with Shannon
pip install anthropic Documentation → Official Anthropic TypeScript SDK - works with Shannon
npm install @anthropic-ai/sdk Documentation → | Status | Type | Meaning |
|---|---|---|
400 | Permintaan tidak valid | Format atau parameter permintaan tidak valid |
401 | Tidak diizinkan | Kunci API tidak valid atau hilang |
429 | Kuota terlampaui | Kuota token atau pencarian terlampaui |
429 | Dibatasi | Terlalu banyak permintaan, perlambat |
500 | Kesalahan server | Kesalahan internal, coba lagi nanti |
{
"error": {
"message": "Invalid API key provided",
"type": "authentication_error",
"code": "invalid_api_key"
}
} Sign in to view and manage your API key.
•••••••••••••••• Sign in Jaga kerahasiaan kunci API Anda. Membuat ulang akan membuat kunci baru dan menonaktifkan yang lama.
Masuk untuk melihat saldo Anda. Setiap panggilan API, baik hosted maupun Shannon, menggunakan saldo yang sama dengan chat: kuota paket hari ini terlebih dahulu, kemudian kredit yang dibeli.
| Model | Jenis | Panggilan | Pengeluaran |
|---|
Belum ada panggilan API-key. Permintaan yang dilakukan dengan kunci Anda akan muncul di sini, dihargai per model.
Harga per model ada di bagian Model & pricing di atas. Hosted model menagih input dan output secara terpisah; model Shannon menagih dengan tarif flat. Keduanya diselesaikan dari saldo Anda dengan harga $5 per 1M kuota tokens. Lihat harga →
Sign in to see your recent API activity.
| Time | Endpoint | Model | Billed tokens | Biaya |
|---|
No API calls yet. Your first request will show up here.
Free tier included with every account. Your key is one click away.