Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ sochain chart BTC tx_count --interval day --json

## API key

Lookups work without a key: 2,500 a day per IP address. With a key, the
Lookups work without a key: at least 2,500 a day per IP address, more when
there's room. With a key, the
account's plan applies. The CLI reads `SOCHAIN_API_KEY`, or a key saved by
`sochain auth login`; `sochain auth status` shows which is used. Never print
the key or pass it on the command line.
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ $ sochain balance BTC bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh
Balance 3.92247777 BTC

$ sochain fees BTC
Suggested fee rate 0.25 sat/vB (the next block's median).
Suggested fee rate 1 sat/vB (the next block's median, rounded up).
...

$ sochain transaction LTC <txid>
Expand Down Expand Up @@ -106,7 +106,8 @@ instead of US dollars. Run `sochain <command> --help` for details and examples.

## API key

Lookups work without a key, up to 2,500 a day per IP address. For more, get a
Lookups work without a key: at least 2,500 a day per IP address, and up to
25,000 when there's room. For more, get a
key at [sochain.com/signin](https://sochain.com/signin) (plans and limits:
[sochain.com/pricing](https://sochain.com/pricing)), then either:

Expand All @@ -133,7 +134,9 @@ sent only to sochain.com, and never printed.
`sochain schema` describes every command as JSON.
- `sochain skill install` adds the SoChain skill to Claude Code and Codex.
- `sochain mcp install` adds the hosted MCP server, `https://sochain.com/mcp`,
to Codex and Claude Code (`--use-api-key` to use your key). By hand:
to Codex and Claude Code. With `--use-api-key` it uses your key: Codex reads
it from `SOCHAIN_API_KEY`, and Claude Code saves it in its own config (or, with
`--project`, reads `SOCHAIN_API_KEY`). By hand:

```sh
codex mcp add sochain --url https://sochain.com/mcp --bearer-token-env-var SOCHAIN_API_KEY
Expand Down
17 changes: 15 additions & 2 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,19 @@ impl Api {
let mut attempt = 0;
let resp = loop {
let resp = self.send(url, accept, true)?;
if resp.status() != StatusCode::TOO_MANY_REQUESTS {
// A 503 that says when to come back (SoChain is briefly busy) is
// waited out like a rate limit; one without Retry-After is not.
let busy = resp.status() == StatusCode::SERVICE_UNAVAILABLE;
if resp.status() != StatusCode::TOO_MANY_REQUESTS
&& !(busy && retry_after(&resp).is_some())
{
break resp;
}
let wait = retry_after(&resp).unwrap_or(1);
attempt += 1;
if busy && (attempt > RATE_LIMIT_RETRIES || wait > MAX_RETRY_WAIT_SECS) {
break resp;
}
if attempt > RATE_LIMIT_RETRIES || wait > MAX_RETRY_WAIT_SECS {
let message = resp
.json::<Value>()
Expand All @@ -174,7 +182,12 @@ impl Api {
});
}
self.note(&format!(
"too many requests at once; retrying in {}",
"{}; retrying in {}",
if busy {
"SoChain is busy"
} else {
"too many requests at once"
},
seconds(wait)
));
sleep(Duration::from_secs(wait));
Expand Down
2 changes: 1 addition & 1 deletion src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ pub fn status(
} else {
writeln!(
out,
"No API key. Lookups still work, up to 2,500 a day per IP address.\n\
"No API key. Lookups still work: at least 2,500 a day per IP address, more when there's room.\n\
Get a key at https://sochain.com/signin, then run `sochain auth login` \
or set {ENV_KEY}."
)?;
Expand Down
9 changes: 5 additions & 4 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::network::Network;
LTCTEST, DOGETEST, ZECTEST), in any case.\n\n\
Output is plain English by default. Pass --json (or set SOCHAIN_JSON=1) for the \
API's JSON reply, unchanged; errors are then JSON on stderr.\n\n\
Lookups work without an API key (2,500 a day per IP address). With a key, your \
Lookups work without an API key (at least 2,500 a day per IP address). With a key, your \
plan's limits apply: run `sochain auth login`, or set SOCHAIN_API_KEY.\n\n\
Exit codes: 0 ok, 1 other error, 2 bad input, 3 not found, 4 SoChain unavailable, \
5 rate limited, 6 API key missing, invalid or not allowed.",
Expand Down Expand Up @@ -533,9 +533,10 @@ pub enum McpCommand {
/// Add https://sochain.com/mcp to Codex and Claude Code
#[command(
after_help = "Uses each agent's own command (`codex mcp add`, `claude mcp add`); nothing\n\
runs locally. Without --use-api-key the server is used without a key (2,500\n\
lookups a day per IP address). With it, the agent reads your key from\n\
SOCHAIN_API_KEY when it starts, so the key itself is not written to its config.\n\
runs locally. Without --use-api-key the server is used without a key (at\n\
least 2,500 lookups a day per IP address). With it, Codex reads your key from\n\
SOCHAIN_API_KEY when it starts, and so does Claude Code with --project; for\n\
Claude Code's user scope the key is saved in Claude Code's own config.\n\
For Cursor and other apps, --print shows what to add.\n\n\
Examples:\n sochain mcp install\n sochain mcp install --use-api-key\n sochain mcp install --print"
)]
Expand Down
Loading
Loading