Skip to content

Quickstart Guides ​

Follow these steps to complete your first sponsored (gasless) User Operation in ≈5 minutes.

1) Create account and project ​

Create Your Account ​

  1. Navigate to the INDID Dashboard
  2. Register with your email and password
  3. Verify your email address by clicking the verification link sent to your inbox

Create Your Project ​

Once logged in to the Dashboard:

  1. Select the Chain: Choose your target blockchain network from the network selector
  2. Create Project: Click the "Create Project" button to open the project creation modal
  3. Configure Project:
    • Enter a project name
    • Add a description (optional)
    • Click "Create" to finalize

Project Dashboard ​

After creating your project, you can access the project dashboard.

2) Get your API Key ​

To retrieve your API keys for SDK integration:

  1. Open your project from the Dashboard
  2. Navigate to "API keys" from the sidebar menu
  3. Manage your API keys:
    • View your Core API Key and Admin API Key
    • Copy API keys to use in your application
    • Regenerate API keys if needed (regeneration invalidates the previous key)

You'll need both API keys:

  • Core API Key: Used for client-side operations with the Core SDK
  • Admin API Key: Used for server-side operations with the Admin SDK (keep this secure and never expose it in client-side code)

3) Send your first User Operation ​

Submit a sponsored operation via INDID (Paymaster sponsorship + Bundler relay behind the scenes).

Install dependencies ​

bash
npm install @indid/indid-core-sdk
npm install @indid/indid-admin-sdk
npm install --save-dev ethers

Script: ETH transfer from a Smart Contract Wallet (client + server) ​

The following end-to-end example shows how to transfer ETH on-chain from a Smart Contract Wallet using both SDK clients:

  • Core SDK in the client environment (browser/app)
  • Admin SDK in the server environment (backend)

Note: Do not use Admin SDK in a browser – keep admin keys on the server.

ts
import { Client } from "@indid/indid-core-sdk"; // client-side
import { AdminClient } from "@indid/indid-admin-sdk"; // server-side
import { ethers } from "ethers";

async function run() {
  const rpcUrl = "https://your-rpc";
  const coreApiKey = "YOUR_CORE_API_KEY";
  const adminApiKey = "YOUR_ADMIN_API_KEY"; // server-only
  const walletPrivateKey = "0x...";

  // ---------------------------
  // Server-side (Node/Backend)
  // ---------------------------
  // Initialize Admin client (server only)
  const adminClient = await AdminClient.init({ rpcUrl, apiKey: adminApiKey });

  // Create the owner wallet (owner EOA)
  const wallet = new ethers.Wallet(walletPrivateKey);

  // Deploy the smart account (server-side)
  const deployRes = await adminClient.createAccount(wallet.address);
  if (deployRes.error) throw new Error(`Deploy failed: ${deployRes.error}`);
  const smartAccount = deployRes.accountAddress;

  // ---------------------------------
  // Client-side (Browser/App/Frontend)
  // ---------------------------------
  const client = await Client.init({ rpcUrl, apiKey: coreApiKey });

  // Prepare ETH transfer (0.001 ETH) from the smart account
  const recipient = "0xRecipient...";
  const builder = await client.prepareSendETH(
    recipient,
    ethers.utils.parseEther("0.001")
  );

  // Sign with the smart account
  await client.signUserOperation(builder);

  // Send the user operation
  const { taskId, userOpHash, error } = await client.sendUserOperation(builder);
  if (error) throw new Error(`Send failed: ${error}`);

  console.log("userOpHash:", userOpHash);
  console.log("taskId:", taskId);

  // Wait for completion (optional)
  const { operationStatus, receipt, reason } = await client.waitTask(taskId);
  console.log("status:", operationStatus);
  if (reason) console.log("reason:", reason);
  if (receipt) console.log("receipt:", receipt);
}

run().catch(console.error);

Example ​

ts
import { Client } from "@indid/indid-core-sdk";
import { AdminClient } from "@indid/indid-admin-sdk";
import { ethers } from "ethers";

async function foo() {
  // initialize client with node provider rpc url and project api key
  const client = await Client.init({ rpcUrl, apiKey: coreApiKey });

  // inizialize admin client on backend-side with admin api key
  const adminClient = await AdminClient.init({
    rpcUrl,
    apiKey: adminApiKey,
  });

  // create a new ethers Wallet for private key
  const wallet = new ethers.Wallet(walletPrivateKey);

  // get smart account address for the wallet
  // will be the same of the deployed one
  const { accountAddress } = await client.getCounterfactualAddress(
    wallet.address
  );

  // deploy smart account on-chain passing the owner wallet address
  // this step is done on backend-side via admin client
  const { error: createErr, accountAddress: address } =
    await adminClient.createAccount(wallet.address);
  if (createErr) {
    // do stuff
  }

  // once the account is deployed, we can use the client to send user operations
  const recipientAddress = "0x...."; // recipient address
  // prepare a user operation to send 0.001 ETH
  const userop = await client.prepareSendETH(
    recipientAddress,
    ethers.utils.parseEther("0.001")
  );

  // sign the user operation with the smart account
  await client.signUserOperation(userop);

  // send the user operation
  const {
    taskId,
    userOpHash,
    error: sendErr,
  } = await client.sendUserOperation(userop);
  if (sendErr) {
    // do stuff
  }

  console.log("userOpHash:", userOpHash);
  console.log("taskId:", taskId);

  // wait for the task to be completed

  // operationStatus: TaskUserOperationStatus;
  //   receipt?: JSON;
  //   reason?: string;
  const { operationStatus, receipt, reason } = await client.waitTask(taskId);

  // do stuff ...
}