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

# Gasless Wallets — Node.js

> Create a wallet and execute a gasless USDC transfer from a Node.js server using @chipi-stack/backend.

<Info>
  **Production apps should pair this with a passkey on the browser side.** This
  page uses a string `encryptKey` for the smoke-test scenario, which is the
  simplest possible flow. For shipping integrations, the `encryptKey` should
  come from a platform passkey — see the [passkey
  quickstart](/sdk/passkeys/quickstart) for the browser flow. The server
  pieces below are identical either way.
</Info>

This page shows the full create-wallet → transfer round trip, lifted from the Chipi staging smoke test that runs in CI on every release. Code is verbatim from the test, with secrets (`CHIPI_PUBLIC_KEY`, `CHIPI_SECRET_KEY`, `CHIPI_BASE_URL`, encrypted private keys) read from environment variables.

## Install

<CodeGroup>
  ```bash npm theme={null}
  npm install @chipi-stack/backend
  ```

  ```bash pnpm theme={null}
  pnpm add @chipi-stack/backend
  ```

  ```bash yarn theme={null}
  yarn add @chipi-stack/backend
  ```
</CodeGroup>

## Initialise the SDK

```ts theme={null}
import { ChipiServerSDK } from "@chipi-stack/backend";

const sdk = new ChipiServerSDK({
  apiPublicKey: process.env.CHIPI_PUBLIC_KEY!,
  apiSecretKey: process.env.CHIPI_SECRET_KEY!,
  // baseUrl is only needed if you're targeting staging or a self-hosted backend
  baseUrl: process.env.CHIPI_BASE_URL, // omit for production
});
```

## Create a wallet

`createWallet` provisions a fresh Starknet account, encrypts the private key with the `encryptKey` you provide, and returns the public key + encrypted private key. Chipi's paymaster covers the deploy transaction.

```ts theme={null}
const externalUserId = `user-${Date.now()}`;

const wallet = await sdk.createWallet({
  params: {
    encryptKey: userPin,        // user-chosen PIN or passkey-derived secret
    externalUserId,             // your user identifier
    chain: "STARKNET",
  },
});

console.log(wallet.publicKey);            // 0x...
console.log(wallet.encryptedPrivateKey);  // ciphertext you store alongside your user
```

Look it up later by your own user ID:

```ts theme={null}
const retrieved = await sdk.getWallet({ externalUserId });
```

## Transfer USDC (gasless)

```ts theme={null}
const txHash = await sdk.transfer({
  params: {
    encryptKey: userPin,
    wallet: {
      publicKey: wallet.publicKey,
      encryptedPrivateKey: wallet.encryptedPrivateKey,
    },
    token: "USDC",
    recipient: "0xRecipientAddress...",
    amount: 1000n, // 0.001 USDC (USDC has 6 decimals — adjust accordingly)
  },
});

console.log(txHash); // 0x... — settles on Starknet mainnet without the user paying gas
```

The transfer is paid for by your service wallet's USDC balance. Check that balance in the dashboard at `/configure/billing`.

## Putting it together

End-to-end, mirroring the smoke test:

```ts theme={null}
import { ChipiServerSDK } from "@chipi-stack/backend";

async function main() {
  const sdk = new ChipiServerSDK({
    apiPublicKey: process.env.CHIPI_PUBLIC_KEY!,
    apiSecretKey: process.env.CHIPI_SECRET_KEY!,
  });

  // 1. Create a wallet for your user
  const externalUserId = `user-${Date.now()}`;
  const wallet = await sdk.createWallet({
    params: { encryptKey: process.env.USER_PIN!, externalUserId, chain: "STARKNET" },
  });

  // 2. Send 0.001 USDC from your funding wallet to the new wallet
  const txHash = await sdk.transfer({
    params: {
      encryptKey: process.env.FUNDING_WALLET_ENCRYPT_KEY!,
      wallet: {
        publicKey: process.env.FUNDING_WALLET_PUBLIC_KEY!,
        encryptedPrivateKey: process.env.FUNDING_WALLET_ENCRYPTED_KEY!,
      },
      token: "USDC",
      recipient: wallet.publicKey,
      amount: 1000n,
    },
  });

  console.log({ wallet: wallet.publicKey, txHash });
}

main();
```

> ✅ Verified against the live API on **2026-05-11**.

## What's next

Reading token balances, PIN/passkey rotation, and session keys are covered by their own smoke tests (`staging-reads.test.ts`, `staging-update-encryption.test.ts`, `staging-sessions.test.ts`) and will land in follow-up doc PRs.
