XChain Platform SDK: Configuration Reference
Constructor Options
All options are passed as a plain object to the XChainSDK constructor. Every field is optional; the SDK will fall back to environment variables and built-in defaults for any field not provided.
const sdk = new XChainSDK(options);
| Option | Type | Default | Description |
|---|---|---|---|
network |
string | NETWORK env var |
Target blockchain and network. See Network Strings for valid values. |
explorerUrl |
string | EXPLORER_URL env var, then the public XChain host for mainnet/testnet, then 'localhost' for regtest |
Hostname or IP of the xchain-explorer API server. See Public Endpoint Defaults. |
explorerPort |
number | EXPLORER_PORT env var or 8080 |
Port of the xchain-explorer API server. Unused when explorerUrl resolves to a full https:// URL (the public default). |
encoderUrl |
string | ENCODER_URL env var, then the public XChain host for mainnet/testnet, then 'localhost' for regtest |
Hostname or IP of the xchain-encoder JSON-RPC server. See Public Endpoint Defaults. |
encoderPort |
number | ENCODER_PORT env var or 3003 |
Port of the xchain-encoder JSON-RPC server. Unused when encoderUrl resolves to a full https:// URL (the public default). |
hubUrl |
string | HUB_API_HOST env var, then the public XChain host for mainnet/testnet, then 'localhost' for regtest |
Hostname or IP of the xchain-hub config oracle. Required for hub discovery. See Public Endpoint Defaults. |
hubPort |
number | HUB_PORT env var or 10000 |
Port of the xchain-hub config oracle. |
hubPollInterval |
number | 60000 |
How often (ms) to re-fetch config from hub after init(). |
timeout |
number | 30000 |
Request timeout in milliseconds applied to all HTTP requests. |
retry |
RetryConfig or false |
See Retry Configuration | Retry policy for transient errors. Pass false to disable retries entirely. |
hooks |
SDKHooks object | {} |
Lifecycle callbacks for requests, responses, errors, and retries. See Request Hooks. |
pool |
PoolConfig object | See Connection Pooling | HTTP keep-alive agent settings for the explorer and encoder clients. |
websocketUrl |
string | WEBSOCKET_URL env var, falls back to explorerUrl |
Hostname of the xchain-explorer WebSocket server. |
websocketPort |
number | WEBSOCKET_PORT env var, falls back to explorerPort |
Port of the xchain-explorer WebSocket server. |
RetryConfig fields
| Field | Type | Default | Description |
|---|---|---|---|
maxRetries |
number | 3 |
Maximum number of retry attempts after the initial request fails. |
baseDelay |
number | 1000 |
Base delay in milliseconds for the first retry. |
maxDelay |
number | 30000 |
Upper bound on retry delay in milliseconds (after backoff). |
backoffFactor |
number | 2 |
Multiplier applied to the delay on each successive retry. |
SDKHooks fields
| Field | Type | Description |
|---|---|---|
onRequest |
function | Called before every HTTP request. Signature: (config) => void where config is the axios request config. |
onResponse |
function | Called after every successful HTTP response. Signature: (response) => void. |
onError |
function | Called when a request fails (after all retries are exhausted). Signature: (error) => void. |
onRetry |
function | Called before each retry attempt. Signature: (attempt, delay, error) => void. |
onWsConnect |
function | Called when WebSocket connection is established. Signature: ({ url }) => void. |
onWsDisconnect |
function | Called when WebSocket connection is closed. Signature: ({ code }) => void. |
onWsMessage |
function | Called for every WebSocket message received. Signature: (msg) => void. |
onWsReconnect |
function | Called before each WebSocket reconnect attempt. Signature: ({ attempt, delay }) => void. |
PoolConfig fields
| Field | Type | Default | Description |
|---|---|---|---|
keepAlive |
boolean | true |
Enable HTTP keep-alive connections. |
keepAliveMsecs |
number | 1000 |
Initial delay (ms) between keep-alive packets. |
maxSockets |
number | 10 |
Maximum concurrent sockets per host. |
maxFreeSockets |
number | 5 |
Maximum idle sockets to keep open per host. |
Config Resolution Priority
When the same setting can be specified in multiple places, the SDK resolves it in this order (highest priority first):
- Constructor options: values passed directly to
new XChainSDK(options). - Hub-discovered endpoints: endpoint URLs and ports fetched from xchain-hub during
init(). Only applies toexplorerUrl,explorerPort,encoderUrl, andencoderPort, and only overlays a field that was not pinned via constructor options. - Environment variables: values read from process environment or a
.envfile. - Public endpoint defaults: for mainnet/testnet networks only, the public XChain Platform hosts (
https://hub.xchain.io,https://explorer.xchain.io,https://encoder.xchain.io). See Public Endpoint Defaults. - Localhost fallback: the last resort, used by regtest networks (inherently local) and any construction with no network at all.
Constructor options always win. Hub discovery fills gaps that explicit options did not cover. Environment variables fill gaps that hub discovery did not cover. For mainnet/testnet, public endpoint defaults fill gaps environment variables did not cover, so a network-only construction (new XChainSDK({ network: 'bitcoin-mainnet' })) already has working explorer, encoder, and hub clients with no other configuration. The localhost fallback only applies to regtest, or when no network is set at all.
Environment Variables
The SDK reads these environment variables at construction time. A .env file in the working directory is loaded automatically via dotenv.
| Variable | Description | Used by |
|---|---|---|
NETWORK |
Network string (e.g. bitcoin-mainnet). See Network Strings. |
Explorer client, Hub connector |
SDK_API_PORT |
Port for the JSON-RPC microservice API server. Default: 3005. |
API server (npm run api) |
SDK_API_KEY |
Bearer token required for all API server methods except ping. No default; the server warns and rejects all non-ping calls when unset. |
API server (npm run api) |
SDK_API_MAX_BATCH |
Maximum calls accepted in one batch request. A non-numeric or non-positive value falls back to the default rather than disabling the cap. Default: 20. |
API server (npm run api) |
SDK_API_RATE_LIMIT |
Requests allowed per window, per credential (per source address when unauthenticated). A junk value falls back to the default; an explicit 0 disables the limiter, which is the only way to turn it off. Default: 300. |
API server (npm run api) |
SDK_API_RATE_WINDOW_MS |
Length of the rate-limit window. Default: 60000 (1 minute). |
API server (npm run api) |
EXPLORER_URL |
Hostname or IP of the xchain-explorer server. | Explorer client |
EXPLORER_PORT |
Port of the xchain-explorer server. | Explorer client |
ENCODER_URL |
Hostname or IP of the xchain-encoder server. | Encoder client |
ENCODER_PORT |
Port of the xchain-encoder server. | Encoder client |
HUB_API_HOST |
Hostname or IP of the xchain-hub server. | Hub connector |
HUB_PORT |
Port of the xchain-hub server. | Hub connector |
HUB_URL |
Full hub base URL used by the interactive REPL (npm run repl), as an alternative to HUB_API_HOST + HUB_PORT. |
REPL |
HUB_API_KEY |
API key sent with hub calls as x-api-key. Required whenever the hub runs keyed. Treat as a credential. |
Hub connector |
XCHAIN_MCP_WIF |
Agent signing key for the MCP server’s write tools. Never logged or echoed. Must be set together with XCHAIN_MCP_POLICY; with either missing the server starts read-only. Configured by the operator, never by the conversation. See MCP Quickstart. Treat as a credential. |
MCP server |
XCHAIN_MCP_POLICY |
Path to the AgentSession policy JSON that bounds what the agent may spend. Required alongside XCHAIN_MCP_WIF; a policy with no spend ceiling is refused, because the MCP rail has no human in the loop. |
MCP server |
XCHAIN_INDEXER_PATH |
Path to a sibling xchain-indexer checkout, used by bin/check-preflight-drift.js to hash the indexer’s action handlers. Falls back to ../xchain-indexer. Development tooling only. |
Drift checker |
CORS_ORIGIN |
CORS origin for the JSON-RPC microservice API server. Disabled when unset. | API server (npm run api) |
STOP_CHECK_INTERVAL |
Poll interval in milliseconds for sdk.start()'s shutdown loop, which sleeps this long between checks of the stop flag set by sdk.stop(). Only relevant when running the SDK as a long-lived process. Default: 5000. |
sdk.start() |
COSIGNER_TOKEN |
Shared bearer token for the optional MuSig2 co-signer sidecar (createCoSignerApp). The sidecar is a local service: bind it to loopback and gate it with this token. No default; see MULTISIG. |
Co-signer sidecar |
Hub Discovery
The SDK can auto-discover explorer and encoder endpoints by querying an xchain-hub instance. This is useful in dynamic or multi-chain deployments where service locations may change.
How it works:
- Pass
hubUrl(and optionallyhubPort) to the constructor. - Call
await sdk.init()after construction. init()callsgetAllConfig()on the hub via JSON-RPC, retrieves the full platform config, and extracts the explorer and encoder endpoints for your configurednetwork.- The SDK re-initializes the explorer and encoder clients with the hub-discovered endpoints, respecting any explicit options you already provided (explicit options always take precedence).
- After the initial fetch,
init()starts a polling timer (default: every 60 seconds) that re-fetches hub config and re-initializes clients if endpoints change.
When init() is required: Only when you rely on hub discovery to resolve service endpoints. If you provide explicit explorerUrl/encoderUrl in the constructor, init() is optional.
Graceful fallback: If init() fails to reach the hub but both explorerUrl and encoderUrl were already provided explicitly, the SDK logs a warning and continues with the explicit config. If the hub is unavailable and no explicit URLs were provided, init() throws an error.
Stopping polling: Call sdk.stop() to halt hub polling and clean up the timer. This is important in server-mode applications during graceful shutdown.
// Hub discovery is safe to call multiple times; each call re-fetches config
await sdk.init();
await sdk.init(); // re-fetches and re-resolves (safe)
sequenceDiagram
participant App
participant SDK
participant Hub
App->>SDK: new XChainSDK(hubUrl, hubPort)
App->>SDK: init()
SDK->>Hub: getAllConfig(), JSON-RPC
Hub-->>SDK: platform config, explorer and encoder endpoints for network
SDK->>SDK: re-initialize explorer and encoder clients, explicit options take precedence
loop every 60 seconds
SDK->>Hub: re-fetch config
Hub-->>SDK: config
SDK->>SDK: re-initialize clients if endpoints changed
end
Public Endpoint Defaults
When only network is specified (no explicit service URLs, no environment overrides, and the network is not regtest), the SDK applies public XChain Platform endpoint defaults so you can query mainnet or testnet with minimal config:
| Service | Default URL |
|---|---|
| Hub | https://hub.xchain.io/{COIN} |
| Explorer | https://explorer.xchain.io |
| Encoder | https://encoder.xchain.io/{COIN} |
{COIN} is the coin prefix derived from your network (e.g. BTC for bitcoin-mainnet, TBTC for bitcoin-testnet). These defaults use HTTPS on port 443; no port number is appended.
Regtest networks always fall through to each client’s own localhost fallback because regtest stacks are inherently local.
// Minimal config: hub, explorer, and encoder all resolve to the public platform
const sdk = new XChainSDK({ network: 'bitcoin-mainnet' });
// Equivalent to:
// { explorerUrl: 'https://explorer.xchain.io',
// hubUrl: 'https://hub.xchain.io/BTC',
// encoderUrl: 'https://encoder.xchain.io/BTC' }
API Server Mode
The SDK ships an optional JSON-RPC HTTP server that exposes all SDK methods over a network interface. This is useful for integrating the SDK into non-Node environments or for running it as a shared microservice.
Starting the server:
SDK_API_PORT=3005 SDK_API_KEY=mysecret NETWORK=bitcoin-mainnet npm run api
The server listens on SDK_API_PORT (default 3005). Every method except ping requires a Bearer authorization header whose value matches SDK_API_KEY. If SDK_API_KEY is not set, the server starts but rejects all non-ping calls with HTTP 401.
Example call:
# Health check (no auth required)
curl -X POST http://localhost:3005 \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"ping","params":{}}'
# Create an action (auth required)
curl -X POST http://localhost:3005 \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer mysecret' \
-d '{"jsonrpc":"2.0","id":2,"method":"create_action","params":{"action":"SEND","params":{"tick":"MYTOKEN","amount":"100","destination":"bc1q..."}}}'
The API server accepts the same environment variables as the SDK constructor (NETWORK, EXPLORER_URL, ENCODER_URL, HUB_API_HOST, etc.) and runs sdk.init() automatically when HUB_API_HOST is configured.
Network Strings
The network option identifies both the blockchain and the network tier. It determines which coin prefix the explorer client uses when building API paths.
| Network String | Coin Prefix | Blockchain | Network |
|---|---|---|---|
bitcoin-mainnet |
BTC |
Bitcoin | Mainnet |
bitcoin-testnet |
TBTC |
Bitcoin | Testnet |
bitcoin-regtest |
RBTC |
Bitcoin | Regtest |
litecoin-mainnet |
LTC |
Litecoin | Mainnet |
litecoin-testnet |
TLTC |
Litecoin | Testnet |
litecoin-regtest |
RLTC |
Litecoin | Regtest |
dogecoin-mainnet |
DOGE |
Dogecoin | Mainnet |
dogecoin-testnet |
TDOGE |
Dogecoin | Testnet |
dogecoin-regtest |
RDOGE |
Dogecoin | Regtest |
Retry Configuration
The SDK automatically retries requests that fail due to transient errors. By default, up to 3 retries are attempted with exponential backoff and ±25% random jitter.
Retryable conditions:
- HTTP 429 (Too Many Requests)
- HTTP 502 (Bad Gateway)
- HTTP 503 (Service Unavailable)
- HTTP 504 (Gateway Timeout)
- Network errors:
ECONNRESET,ECONNREFUSED,EPIPE - Timeouts:
ECONNABORTED
Retry-After header support: When the server returns a Retry-After header (on 429 responses), the SDK parses it, supporting both integer seconds (120) and HTTP-date format (Wed, 21 Oct 2015 07:28:00 GMT); and waits exactly that long instead of the computed backoff. The delay is still capped at maxDelay.
Backoff formula: delay = baseDelay * backoffFactor^attempt, capped at maxDelay, with ±25% jitter applied.
Custom retry settings
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
retry: {
maxRetries: 5,
baseDelay: 500, // start at 500ms
maxDelay: 60000, // cap at 60 seconds
backoffFactor: 3 // triple each time
}
});
Disabling retry
Pass false to disable all retry logic. Requests will fail immediately on any error.
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
retry: false
});
Observing retries via hooks
Use the onRetry hook to log retry attempts:
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
hooks: {
onRetry: (attempt, delay, error) => {
console.warn(`Retry #${attempt} in ${delay}ms after: ${error.message}`);
}
}
});
Connection Pooling
The explorer and encoder clients share an HTTP keep-alive agent. Keeping connections open reduces latency for repeated requests to the same host. The default settings suit most applications; tune them for high-throughput workloads.
Default pool settings: keepAlive true, keepAliveMsecs 1000, maxSockets 10, maxFreeSockets 5.
High-throughput example
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
explorerUrl: 'explorer.example.com',
pool: {
keepAlive: true,
keepAliveMsecs: 500,
maxSockets: 50,
maxFreeSockets: 20
}
});
Disabling keep-alive
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
explorerUrl: 'explorer.example.com',
pool: {
keepAlive: false
}
});
Request Hooks
Hooks are lifecycle callbacks that fire at key points in the request pipeline. They receive read-only context and are intended for logging, metrics, and debugging. Not for modifying requests.
| Hook | When it fires | Signature |
|---|---|---|
onRequest |
Before every HTTP request is sent | (config) => void: config is the axios request config object |
onResponse |
After every successful HTTP response | (response) => void: response is the full axios response object |
onError |
After all retries fail | (error) => void: error is the final axios error |
onRetry |
Before each retry delay | (attempt, delay, error) => void |
Example: logging all requests and responses
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
explorerUrl: 'explorer.example.com',
hooks: {
onRequest: (config) => {
console.log(`[SDK] --> ${config.method.toUpperCase()} ${config.baseURL}${config.url}`);
},
onResponse: (response) => {
console.log(`[SDK] <-- ${response.status} ${response.config.url}`);
},
onError: (error) => {
console.error(`[SDK] ERR ${error.message}`);
},
onRetry: (attempt, delay, error) => {
console.warn(`[SDK] Retry #${attempt} in ${delay}ms: ${error.message}`);
}
}
});
Code Examples
Explicit config (no hub)
Provide all service URLs directly. No async initialization needed.
const XChainSDK = require('./index.js');
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
explorerUrl: 'explorer.example.com',
explorerPort: 8080,
encoderUrl: 'encoder.example.com',
encoderPort: 3003,
timeout: 15000
});
// Use immediately; no init() required
const balances = await sdk.getBalances('bc1qmyaddress');
Hub discovery
Let the hub resolve all service endpoints automatically.
const XChainSDK = require('./index.js');
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
hubUrl: 'hub.example.com',
hubPort: 10000
});
await sdk.init(); // fetches endpoints from hub, starts polling
const balances = await sdk.getBalances('bc1qmyaddress');
// Graceful shutdown
sdk.stop();
Mixed: explicit options + hub fills gaps
Provide some endpoints explicitly; let hub fill in the rest.
const XChainSDK = require('./index.js');
const sdk = new XChainSDK({
network: 'bitcoin-mainnet',
explorerUrl: 'my-explorer.example.com', // explicit; hub cannot override this
hubUrl: 'hub.example.com' // hub will provide encoder endpoints
});
await sdk.init(); // hub provides encoderUrl/encoderPort; explorerUrl stays as given
const result = await sdk.send(
{ tick: 'MYTOKEN', amount: '10', destination: 'bc1qrecipient' },
{ pubkey: '02abc...', change: 'bc1qchange', utxos: [...] }
);
Custom retry
Aggressive retry for an unreliable network.
const XChainSDK = require('./index.js');
const sdk = new XChainSDK({
network: 'dogecoin-mainnet',
explorerUrl: 'explorer.example.com',
timeout: 60000,
retry: {
maxRetries: 10,
baseDelay: 2000,
maxDelay: 120000,
backoffFactor: 2
}
});
Hooks logging
Log all SDK network activity to a file or monitoring system.
const XChainSDK = require('./index.js');
const fs = require('fs');
function log(msg) {
fs.appendFileSync('sdk.log', new Date().toISOString() + ' ' + msg + '\n');
}
const sdk = new XChainSDK({
network: 'litecoin-mainnet',
explorerUrl: 'explorer.example.com',
hooks: {
onRequest: (cfg) => log(`--> ${cfg.method.toUpperCase()} ${cfg.url}`),
onResponse: (res) => log(`<-- ${res.status} ${res.config.url}`),
onError: (err) => log(`ERR ${err.message}`),
onRetry: (n, delay, err) => log(`RETRY #${n} in ${delay}ms: ${err.message}`)
}
});
Environment variable config
Set variables in .env and construct the SDK with no options at all.
# .env
NETWORK=bitcoin-mainnet
EXPLORER_URL=explorer.example.com
EXPLORER_PORT=8080
ENCODER_URL=encoder.example.com
ENCODER_PORT=3003
const XChainSDK = require('./index.js');
// All config read from .env / process.env
const sdk = new XChainSDK();
const balances = await sdk.getBalances('bc1qmyaddress');
Copyright © 2025–2026 Dankest, LLC
Based on XChain Platform by Dankest, LLC – https://dankest.llc
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-or-later) with a commercial license available for proprietary use.
You may use, modify, and distribute this material under the terms of the License. See LICENSE and NOTICE for full terms. See the licensing overview.