> ## 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.

# SELAT Router SDK Signers

> Choose a SELAT Router SDK signer for TypeScript: private key, Circle Agent Wallet, HTTP remote signer, custom remote signer, or Circle Developer-Controlled Wallet.

# SELAT Router SDK Signers

> Choose a signing model that matches your application’s runtime, custody boundary, and deployment environment.

The SELAT Router SDK accepts a `PaymentSigner` when you construct `RouterClient`. A signer supplies the address and EIP-712 signature needed to pay a valid challenge returned through SELAT Router. The package exposes five supported creation paths: a private-key signer, a Circle Agent Wallet signer, an HTTP remote signer, a custom remote signer, and a Circle Developer-Controlled Wallet signer. [1]

## Choose a signer

The table below is the fastest way to select a production-appropriate option. It emphasizes where signing material lives rather than treating all signers as equivalent. [1]

| Signer                                        | Best for                                                         | Where signing happens                                      | Suitable for typical serverless functions?                                                 |
| --------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `createViemSigner`                            | Local prototypes and controlled development environments         | Inside the application process with a supplied private key | Technically possible, but avoid placing long-lived private keys in a function environment. |
| `createCircleAgentWalletSigner`               | Long-running Node.js services using an authenticated Circle CLI  | The local Circle CLI / Circle Agent Wallet flow            | Usually no; use a remote signer when the CLI session is unavailable.                       |
| `createHttpRemoteSigner`                      | Serverless applications and services with a dedicated signer API | Your HTTPS signing service                                 | Yes. This is the serverless-oriented option.                                               |
| `createRemoteSigner`                          | Existing HSM, KMS, or proprietary signing infrastructure         | Your caller-provided signing transport                     | Yes, when the transport is safe and reliable.                                              |
| `createCircleDeveloperControlledWalletSigner` | Applications already using Circle Developer-Controlled Wallets   | Circle’s developer-controlled wallet API                   | Yes, when credentials are held in a secure server-side environment.                        |

> **Security principle:** Keep long-lived signing material outside browser code and untrusted client environments. Use a server-side signer boundary for production systems. [1]

## Private-key signer

Use a private key only when in-process key handling is appropriate, such as a short-lived local prototype. Store the value in a secret manager rather than source control, and do not expose it to the browser. [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
});
```

`RouterClient` also accepts a `privateKey` option directly. Passing an explicitly constructed signer is generally clearer because it keeps signer selection visible in application code. [1]

## Circle Agent Wallet signer

Use a Circle Agent Wallet signer when the application runs in a Node.js environment where the Circle CLI is available and authenticated. Install the SDK and Circle CLI package in the same application so the SDK can resolve the CLI without relying on a globally installed binary. [1]

```bash theme={null}
npm install @selat-ai/router-client @circle-fin/cli
```

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

const signer = createCircleAgentWalletSigner({
  address: process.env.SELAT_SIGNER_ADDRESS as `0x${string}`,
  chain: "base"
});

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

The signer invokes the local `circle` CLI. Before using it, complete Circle’s Agent Wallet setup and login flow, and confirm the selected wallet has an available Gateway balance on the chain used by `RouterClient`. [1] [2]

### Next.js and Node deployment packaging

The SDK exports `CIRCLE_AGENT_WALLET_NEXT_TRACE_INCLUDES` for Next.js deployments that must include the CLI and its dependencies in the traced function output. This configuration handles packaging only; the executing environment must still have an authenticated Circle CLI session and a compatible writable runtime. [1]

```js theme={null}
import { CIRCLE_AGENT_WALLET_NEXT_TRACE_INCLUDES } from "@selat-ai/router-client";

/** @type {import("next").NextConfig} */
const nextConfig = {
  outputFileTracingIncludes: {
    "/api/your-paid-route": CIRCLE_AGENT_WALLET_NEXT_TRACE_INCLUDES
  }
};

export default nextConfig;
```

For a conventional managed serverless function, the local CLI and its authenticated session are normally not present. In that environment, use `createHttpRemoteSigner` instead of attempting to invoke a local Circle CLI. [1]

## HTTP remote signer for serverless workloads

`createHttpRemoteSigner` is the recommended path when your application runs in serverless functions, edge-adjacent application tiers, or another environment that cannot host an authenticated Circle CLI. It sends a signing request to an HTTPS service you operate and also handles Gateway owner-address resolution for smart-contract-account wallets. [1]

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

const signer = createHttpRemoteSigner({
  address: process.env.SELAT_SIGNER_ADDRESS as `0x${string}`,
  endpoint: process.env.SELAT_SIGNER_API_URL as string,
  token: process.env.SELAT_SIGNER_API_TOKEN // optional bearer token
});

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

Your signing service receives `POST { address, typedData }` and returns `{ "signature": "0x..." }`. Protect this service as a signing boundary: authenticate callers, scope its authority, validate the request policy, and retain audit records appropriate for your environment. [1]

## Custom remote signer

Use `createRemoteSigner` when your application already has a signing service, hardware security module, key-management service, or custom authorization protocol. The SDK delegates all transport behavior to the supplied callback. [1]

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

const signer = createRemoteSigner(
  process.env.SELAT_SIGNER_ADDRESS as `0x${string}`,
  async ({ address, typedData }) => {
    const response = await fetch(
      process.env.SELAT_SIGNER_API_URL as string,
      {
        method: "POST",
        headers: {
          "content-type": "application/json",
          authorization: `Bearer ${process.env.SELAT_SIGNER_API_TOKEN}`
        },
        body: JSON.stringify({ address, typedData })
      }
    );

    if (!response.ok) {
      throw new Error(`Signing service returned ${response.status}`);
    }

    const body = (await response.json()) as { signature: `0x${string}` };
    return body.signature;
  }
);

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

Choose `createHttpRemoteSigner` instead when your endpoint follows the standard HTTP contract above and you want the SDK’s additional Gateway owner-address resolution. [1]

## Circle Developer-Controlled Wallet signer

Use this signer when the application already signs through a Circle Developer-Controlled Wallet. Keep the API key and entity secret in a server-side secret manager; never deliver them to a frontend application. [1]

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

const signer = createCircleDeveloperControlledWalletSigner({
  address: process.env.SELAT_SIGNER_ADDRESS as `0x${string}`,
  apiKey: process.env.SELAT_CIRCLE_API_KEY!,
  entitySecret: process.env.SELAT_CIRCLE_ENTITY_SECRET!,
  walletId: process.env.SELAT_CIRCLE_WALLET_ID
});

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

The signer options also support `walletAddress`, `blockchain`, `chain`, `memo`, `baseUrl`, and `userAgent` when the wallet deployment requires explicit configuration. [1]

## Test the signing path

After selecting a signer, make a small paid request against a known endpoint and handle the returned `Response` as you would with native `fetch`. A wallet must have a spendable Gateway balance on the selected chain before a paid request can settle. [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());
```

For client options, payment protocol preference, request timeouts, and error classes, see [RouterClient](/docs/selat-sdk/router-client). For an end-to-end setup, see the [SDK Quickstart](/docs/selat-sdk/quickstart).

## References

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

[2]: https://developers.circle.com/agent-stack/agent-wallets/quickstart "Circle Agent Wallet quickstart"
