> ## Documentation Index
> Fetch the complete documentation index at: https://selat.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# RouterClient: TypeScript API Reference

> Use RouterClient in the SELAT Router SDK to send fetch-like paid requests, select x402 or MPP, configure a signer, set timeouts, handle payment challenges, and claim refunds.

# RouterClient: TypeScript API Reference

> `RouterClient` is the SELAT Router SDK entry point for TypeScript applications that need fetch-like access to paid endpoints.

`RouterClient` sends a request through SELAT Router, returns an unpaid upstream response unchanged when no payment is required, and completes one signed payment replay only when the router returns a valid `402 Payment Required` challenge. It supports a private key or any SDK-compatible `PaymentSigner`. [1]

```ts theme={null}
import { RouterClient, createViemSigner } from "@selat-ai/router-client";

const signer = createViemSigner(
  process.env.X402_CLIENT_PRIVATE_KEY as `0x${string}`
);

const client = new RouterClient({
  chain: "base",
  signer
});
```

## Constructor

```ts theme={null}
new RouterClient({
  chain,
  privateKey,
  signer,
  routerUrl,
  requestTimeoutMs,
  defaultHeaders
})
```

The `chain` option is required. You must supply a `signer` or a `privateKey`; when a signer is supplied, it is used as the signing implementation. [1]

| Option             | Type                     | Required                        | Default                   | Description                                                                         |
| ------------------ | ------------------------ | ------------------------------- | ------------------------- | ----------------------------------------------------------------------------------- |
| `chain`            | `SupportedChainName`     | Yes                             | None                      | Chain key used to select a compatible payment option from the challenge.            |
| `signer`           | `PaymentSigner`          | One of `signer` or `privateKey` | None                      | A constructed signer object for the selected wallet or signing service.             |
| `privateKey`       | `0x${string}`            | One of `signer` or `privateKey` | None                      | Creates an in-process Viem signer. Use only where local key handling is acceptable. |
| `routerUrl`        | `string`                 | No                              | `https://router.selat.ai` | SELAT Router base URL.                                                              |
| `requestTimeoutMs` | `number`                 | No                              | `30000`                   | Timeout applied to each router request leg.                                         |
| `defaultHeaders`   | `Record<string, string>` | No                              | `{}`                      | Headers merged into every request before request-specific headers.                  |

## Send a paid request with `fetch`

`client.fetch(input, init?)` accepts a full target URL and a fetch-compatible request initializer. It returns a standard `Promise<Response>`, so applications can use familiar status, header, and body handling. [1]

```ts theme={null}
const response = await client.fetch(
  "https://upstream.example.com/v1/data",
  {
    method: "GET"
  }
);

if (!response.ok) {
  throw new Error(`Upstream request failed: ${response.status}`);
}

console.log(await response.text());
```

### Request lifecycle

The payment flow consists of a maximum of two router requests for one `fetch` call. The SDK does not sign or replay ordinary non-402 responses. [1]

| Step                         | SDK behavior                                                                                                                  | Outcome                                                         |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| 1. Route the request         | Builds a SELAT Router proxy URL and sends the original method, body, headers, and abort signal.                               | The upstream result is returned when it is not `402`.           |
| 2. Parse a payment challenge | For a `402`, validates the `x-selat-quote-id` and `payment-required` headers.                                                 | A malformed or incompatible challenge raises `QuoteParseError`. |
| 3. Build a payment           | Selects a compatible `GatewayWalletBatched` accept option for the chosen chain and asks the signer for the EIP-712 signature. | Produces a payment payload.                                     |
| 4. Replay once               | Re-sends the routed request with `PAYMENT-SIGNATURE` and the quote ID.                                                        | Returns the final upstream `Response`.                          |

Each of the two router request legs receives its own `requestTimeoutMs` window. Set a value that accommodates your expected upstream latency, but use an `AbortSignal` as well when the caller needs independent cancellation. [1]

## Configure request options

`RouterFetchOptions` extends the standard `RequestInit` options and adds `preferProtocol`. Use normal `fetch` options for HTTP method, headers, request body, and cancellation. [1]

| Option           | Type               | Default | Description                                                                                              |
| ---------------- | ------------------ | ------- | -------------------------------------------------------------------------------------------------------- |
| `method`         | `string`           | `GET`   | HTTP method forwarded to the target endpoint.                                                            |
| `headers`        | `HeadersInit`      | None    | Request-specific headers. These are merged with `defaultHeaders`; request headers can override defaults. |
| `body`           | `BodyInit \| null` | None    | Request body for POST, PUT, PATCH, and other body-bearing methods.                                       |
| `signal`         | `AbortSignal`      | None    | Cancels the active request leg.                                                                          |
| `preferProtocol` | `"x402" \| "mpp"`  | `"mpp"` | Adds a protocol preference hint as `x-selat-prefer-protocol`.                                            |

### POST example

```ts theme={null}
const response = await client.fetch("https://upstream.example.com/v1/jobs", {
  method: "POST",
  headers: {
    "content-type": "application/json"
  },
  body: JSON.stringify({
    query: "pricing"
  }),
  preferProtocol: "x402"
});
```

> **Protocol preference is a hint.** Choose `x402` or `mpp` only when your integration needs to express a rail preference; the default is `mpp`. [1]

## Bind a base URL with `createFetch`

Use `createFetch({ baseUrl })` to create a fetch-like function for a known upstream. It resolves each relative path against the base URL, then routes the resulting absolute URL through the same payment flow. [1]

```ts theme={null}
const apiFetch = client.createFetch({
  baseUrl: "https://upstream.example.com"
});

const response = await apiFetch("/v1/data", {
  method: "GET"
});
```

This pattern keeps endpoint call sites concise while retaining the same signer, timeout, headers, and protocol configuration.

## Claim and track refunds

Use the quote ID from a completed paid request to create a refund claim. `refundClaim(quoteId)` returns the new `RefundRequest`. Use `refundQuery(quoteId)` to retrieve its latest status. Both methods authenticate the request with the `RouterClient` signer. [1]

```ts theme={null}
const quoteId = "selatx<quote-id>";

const refund = await client.refundClaim(quoteId);
console.log(refund.id, refund.status);

const status = await client.refundQuery(quoteId);
console.log(status.status, status.refundTxId);
```

| Method                 | Returns                       | Description                                          |
| ---------------------- | ----------------------------- | ---------------------------------------------------- |
| `refundClaim(quoteId)` | `Promise<RefundRequest>`      | Creates a refund claim for the quote ID.             |
| `refundQuery(quoteId)` | `Promise<RefundStatusResult>` | Retrieves the latest refund status for the quote ID. |

`RefundRequest` includes the claim `id`, `quoteId`, requesting `wallet`, current `status`, and `createdAt` timestamp. `RefundStatusResult` includes the `quoteId` and `status`; it can also include `chainId` and `refundTxId` when available. A refund status is one of `new`, `pending_review`, `approved`, `processing`, `succeeded`, or `failed`.

If the Router rejects the request or cannot return a valid result, either method throws an `Error` whose message includes the HTTP status and the returned detail. Handle this separately from payment-challenge parsing errors.

## Handle SDK errors

The SDK exports a base error type and two specialized errors. Catch the most specific type that helps your application provide a useful recovery path. [1]

| Error                     | When it occurs                                                                                                              | Recommended response                                                                                 |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `RouterClientConfigError` | `chain` is missing or neither a signer nor private key is available.                                                        | Correct application configuration before retrying.                                                   |
| `QuoteParseError`         | A `402` challenge is missing required headers, contains invalid data, or lacks a compatible Gateway-batched payment option. | Inspect the endpoint and selected chain; do not treat the response as payable without a valid quote. |
| `RouterSdkError`          | Base class for SDK-specific errors.                                                                                         | Use when a shared SDK error boundary is sufficient.                                                  |

```ts theme={null}
import {
  QuoteParseError,
  RouterClientConfigError,
  RouterSdkError
} from "@selat-ai/router-client";

try {
  const response = await client.fetch("https://upstream.example.com/v1/data");
  console.log(await response.text());
} catch (error) {
  if (error instanceof RouterClientConfigError) {
    console.error("Check the SELAT chain and signer configuration.");
  } else if (error instanceof QuoteParseError) {
    console.error("The endpoint returned an invalid or incompatible payment challenge.");
  } else if (error instanceof RouterSdkError) {
    console.error("SELAT Router SDK error:", error.message);
  } else {
    throw error;
  }
}
```

## Select a signer and chain

Use the [Signers](/docs/selat-sdk/signers) guide to choose a private key, Circle Agent Wallet, HTTP remote signer, custom remote signer, or Circle Developer-Controlled Wallet. The `chain` must match a payment option offered by the returned challenge and the wallet’s available Gateway balance. See [Chains](/docs/chains) for the fund chains and the outbound settlement rails; for the exact set a specific runtime accepts, query its payment tooling. [1]

For the first complete request, continue to the [SDK Quickstart](/docs/selat-sdk/quickstart). For source examples, see [SDK Examples](/docs/selat-sdk/examples).

## References

[1]: https://www.npmjs.com/package/@selat-ai/router-client "SELAT Router SDK package"
