> For the complete documentation index, see [llms.txt](https://docs.spacecoin.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.spacecoin.org/spacerouter-proxy/service-user-guide/javascript-sdk.md).

# JavaScript SDK

### Install

```bash
npm install @spacenetwork/spacerouter
```

Requires Node.js 18 or later. Browser and Bun support are on the roadmap.

### SPACE-payment example

```ts
import { SpaceRouter, SpaceRouterSPACE } from "@spacenetwork/spacerouter";

const payment = new SpaceRouterSPACE({
  gatewayMgmtUrl: "https://gateway.spacerouter.org",
  wallet,                                          // your ClientPaymentWallet
});

const router = new SpaceRouter("0xYOUR_WALLET_ADDRESS", {
  gatewayUrl: "https://gateway.spacerouter.org",
  payment,
  region: "KR",
  ipType: "residential",
});

const response = await router.get("https://httpbin.org/ip");
console.log(await response.json());
router.close();
```

The first positional argument is the consumer's wallet address (lowercase 0x-hex). The `payment` helper signs the per-request EIP-191 challenge that the gateway requires.

### Constructor

```ts
new SpaceRouter(payerAddress: string, options: {
  gatewayUrl?: string;             // default: "https://gateway.spacerouter.org"
  payment: SpaceRouterSPACE;       // required — signs per-request challenges
  protocol?: "http";               // "http" only — socks5 not supported in v1.5+
  region?: string;                 // 2-letter ISO country code
  ipType?: "residential" | "mobile" | "business" | "hosting";
  timeout?: number;                // default: 30000 (ms)
})
```

### Methods

```ts
await router.request(method, url, options?)
await router.get(url, options?)
await router.post(url, options?)
await router.put(url, options?)
await router.patch(url, options?)
await router.delete(url, options?)
await router.head(url, options?)

// Per-request routing override
const krRouter = router.withRouting({ region: "KR", ipType: "residential" });

// Always close when done
router.close();
```

`options` accepts `headers`, `body`, and an `AbortSignal`:

```ts
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 5000);

const r = await router.post("https://api.example.com/v1/items", {
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "widget" }),
  signal: ctrl.signal,
});
```

### The response object

```ts
interface ProxyResponse {
  status: number;
  headers: Record<string, string>;
  body: ReadableStream;
  text(): Promise<string>;
  json(): Promise<unknown>;
  nodeId: string;  // ID of the Provider that served this request
}
```

### Errors

All errors extend `SpaceRouterError`:

| Class                   | HTTP | Raised when                                                                                                            |
| ----------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------- |
| `AuthenticationError`   | 407  | Payment headers missing or challenge signature rejected.                                                               |
| `QuotaExceededError`    | 402  | Escrow balance below the request's price, or legacy `Proxy-Authorization: Basic` detected (`api_key_auth_deprecated`). |
| `RateLimitError`        | 429  | Rate limited. Has `retryAfter`.                                                                                        |
| `NoNodesAvailableError` | 503  | No Provider matches your region/type filter.                                                                           |
| `UpstreamError`         | 502  | Provider couldn't reach the target site.                                                                               |

```ts
import { NoNodesAvailableError } from "@spacenetwork/spacerouter";

try {
  await router.get("https://httpbin.org/ip");
} catch (err) {
  if (err instanceof NoNodesAvailableError) {
    console.log("No matching nodes — try another region");
  } else {
    throw err;
  }
}
```

### Pay with SPACE

The JavaScript SDK uses on-chain SPACE payment as its only auth mechanism — every request constructed via `SpaceRouter` is paid per byte from the consumer's escrow balance. See the [Pay with SPACE guide](/spacerouter-proxy/service-user-guide/pay-with-space-v1.5.md) for the wallet/escrow setup, the protocol details, and the matching Python reference implementation.
