Onboarding a machine to the peaq network can be done in various ways, but the most straightforward approach is by using the JavaScript SDK to create a DID Document for the machine.

Before deploying to the peaq mainnet, developers are strongly encouraged to test their implementations on the agung testnet. This ensures that machine onboarding, verification, and data storage mechanisms function correctly before deploying to an environment with real monetary value.

Prerequisites

Before onboarding a machine, it is recommended you have an understanding of:

Instructions

The JavaScript SDK provides a developer-friendly way to:

  • Create a DID Document for a machine.
  • Define the machine’s cryptographic identity using EcdsaSecp256k1, Ed25519, or Sr25519 based on the wallet that will be used to create signatures.
  • Add service endpoints to link ownership and storage solutions.
  • Store and retrieve DID-related information from the peaq blockchain.

1. Installing ethers & peaq js

To get started, install:

  • ethers - library used for wallet generation and token transfer.
  • peaq network sdk - generates DID Documents and offers peaq storage.

In your local node environment run:

npm install ethers
npm install @peaq-network/sdk

📌 If you are having trouble please refer to the SDK Installation Guide.

2. Creating a Machine Wallet

Each machine onboarded to the peaq network needs a unique cryptographic identity. This is achieved by creating a dedicated wallet that represents the machine. The wallet enables the machine to sign data, authenticate itself, and perform transactions securely on the network. Since the peaq network is EVM-compatible, we use the ECDSA (Elliptic Curve Digital Signature Algorithm) scheme for key management. This allows machines to sign messages and execute transactions using EVM-standard tools.

The example below shows how to generate a new wallet using the ethers npm package:

import { Wallet } from "ethers";

// A simple keyring for the machine wallet
class ECDSAKeyring {
    constructor(privateKey) {
      if (privateKey) {
        this.wallet = new Wallet(privateKey);
      } else {
        this.wallet = Wallet.createRandom(); // generates new key
      }
    }
    getAddress() {
      return this.wallet.address;
    }
    getPrivateKey() {
      return this.wallet.privateKey;
    }
    async signMessage(message) {
      return this.wallet.signMessage(message);
    }
}

async function main(){
    // Connect the device to your application logic here
    
    // Create a new EVM-compatible wallet for the machine
    const machineWallet = new ECDSAKeyring();

    // Retrieve the wallet's public address (used to identify the machine on-chain)
    console.log("Machine Address:", machineWallet.getAddress());

    // Retrieve the private key (keep this secure and never share it)
    console.log("Private Key:", machineWallet.getPrivateKey());
}

main();

The ECDSAKeyring class abstracts the creation and usage of an EVM-compatible wallet. It provides access to the machine’s public address and private key, and exposes a signMessage method that will be used later for signing operations and authentication.

Never share or expose the machine’s private key. Possession of this key allows anyone to impersonate the machine, sign data, and perform transactions on its behalf. Losing the key means losing access and control over the machine’s on-chain identity.
This is not the only way to onboard machines of the network. Sometimes private keys are not necessary when using Machine Smart Accounts. Learn more about Machine Smart Accounts in the Machine Station Factory section. Coming Soon

3. Token Transfer

In order for a machine to interact with the peaq network, it must be able to execute on-chain transactions — such as registering itself, signing data, or interacting with smart contracts. On EVM-compatible networks like peaq, every write operation to the blockchain requires a fee paid in the network’s native token.

This fee, often referred to as gas, compensates the network for computation and storage resources, and helps maintain network integrity by preventing spam or malicious activity.

After creating a wallet for your machine, you must transfer a small amount of the native token from your admin wallet to the machine wallet. This enables the machine to independently perform transactions on the blockchain. If you have no tokens please checkout our faucet page to receive funds.

The code below demonstrates how to transfer 1 token from an admin account to the machine’s wallet:

import { ethers, Wallet } from "ethers";
import { Sdk } from "@peaq-network/sdk";

// A simple keyring for the machine wallet
class ECDSAKeyring {
    constructor(privateKey) {
      if (privateKey) {
        this.wallet = new Wallet(privateKey);
      } else {
        this.wallet = Wallet.createRandom(); // generates new key
      }
    }
    getAddress() {
      return this.wallet.address;
    }
    getPrivateKey() {
      return this.wallet.privateKey;
    }
    async signMessage(message) {
      return this.wallet.signMessage(message);
    }
}

// Load the admin wallet
async function getAdmin(){
    const provider = new ethers.JsonRpcProvider("https://peaq-agung.api.onfinality.io/public"); // agung endpoint for testnet
    const adminPrivateKey = "0xADMIN_PRIVATE_KEY"; // Replace with admin's secure private key
    return new ethers.Wallet(adminPrivateKey, provider);
}

// Transfer native tokens from admin to machine
async function transferNativeToken(adminWallet, machineWallet) {
    const tx = await adminWallet.sendTransaction({
      to: machineWallet.getAddress(),
      value: ethers.parseEther("1") // transfers 1 token over
    });
  
    console.log("Transaction sent:", tx.hash);
    await tx.wait();
    console.log("Transaction confirmed.");
}

async function main(){	
	const MACHINE_PRIVATE = "0xMACHINE_PRIVATE_KEY"; // Replace with your machine's actual private key
    const machineWallet = new ECDSAKeyring(MACHINE_PRIVATE);
    const adminWallet = await getAdmin();

    await transferNativeToken(adminWallet, machineWallet);
}

main();

🧪 This example uses the agung testnet RPC endpoint. Be sure to switch to the peaq mainnet when you’re ready to onboard real machines in production.

After running this script, your machine wallet will hold 1 native token, making it capable of executing transactions on the peaq network.

4. Creating a Machine DID Document

Once a wallet and funding are in place, the next step is to register a Decentralized Identifier (DID) Document for the machine. This DID represents the machine’s on-chain identity on the peaq network.

A DID Document serves as a verifiable data structure that links the machine’s cryptographic keys to a unique identifier. It allows machines to authenticate themselves, prove ownership of data, and interact securely within the network.

In this example, we use the peaq JavaScript SDK to register a DID for the machine on the agung testnet.

The DID Document contains:

  • Verification Methods - Public keys that allow others to verify signatures made by the machine.
  • Service Endpoints - Useful metadata such as the machine’s admin wallet address or off-chain services.
import { ethers, Wallet } from "ethers";
import { Sdk } from "@peaq-network/sdk";

class ECDSAKeyring {
    constructor(privateKey) {
      if (privateKey) {
        this.wallet = new Wallet(privateKey);
      } else {
        this.wallet = Wallet.createRandom(); // generates new key
      }
    }
    getAddress() {
      return this.wallet.address;
    }
    getPrivateKey() {
      return this.wallet.privateKey;
    }
    async signMessage(message) {
      return this.wallet.signMessage(message);
    }
}

// Create a new DID on chain
async function generateDID(machineWallet, adminWallet){
    const HTTPS_BASE_URL = "https://peaq-agung.api.onfinality.io/public"; // agung testnet endpoint

    const sdk = await Sdk.createInstance({
        baseUrl: HTTPS_BASE_URL,
        chainType: Sdk.ChainType.EVM
    });

    const name = "project_name"; // Replace with your project/DePIN specific name
    
    const customFields = {
        verifications: [{
            type: "EcdsaSecp256k1RecoveryMethod2020"
        }],
        services: [
            {
                id: '#admin',
                type: 'admin',
                data: `${adminWallet.address}`
            }
        ]
    };

    // Create a transaction object to register the DID
    const tx = await sdk.did.create({
        name: name,
        address: machineWallet.getAddress(),
        customDocumentFields: customFields
    });

    // Submit the transaction to the network using the machine’s private key
    const receipt = await Sdk.sendEvmTx({
        tx: tx,
        baseUrl: HTTPS_BASE_URL,
        seed: machineWallet.getPrivateKey()
    });
    
    console.log("DID Document registered with receipt:", receipt);
}

async function main(){	
    const MACHINE_PRIVATE = "0xMACHINE_PRIVATE_KEY"; // Replace with your machine key
    const ADMIN_PRIVATE = "0xADMIN_PRIVATE_KEY"; // Replace with your admin key

    const machineWallet = new ECDSAKeyring(MACHINE_PRIVATE);
    const adminWallet = new ECDSAKeyring(ADMIN_PRIVATE);

    await generateDID(machineWallet, adminWallet);
}

main();

The code above registers a DID Document that links the machine’s address with a verification method based on the wallet the machine is tied to. A reference to the admin account responsible for it is added as well. By submitting this transaction from the machine’s wallet, the peaq network cryptographically claims that the machine is the entity creating this identity.

📌 For more advanced DID operations, including updates, deactivation, or retrieval, refer to the full reference: DID Operations.

Putting it all together

The code below demonstrates the complete flow for onboarding a machine to the peaq network using the agung testnet. This full example includes:

  1. Creating a machine wallet.
  2. Loading an administrator wallet (with native tokens).
  3. Transferring tokens to the machine wallet.
  4. Registering a DID Document that represents the machine’s on-chain identity.
import { ethers, Wallet } from "ethers";
import { Sdk } from "@peaq-network/sdk";

// Simple keyring class for managing EVM-compatible wallets
class ECDSAKeyring {
    constructor(privateKey) {
        this.wallet = privateKey ? new Wallet(privateKey) : Wallet.createRandom();
    }
    getAddress() {
        return this.wallet.address;
    }
    getPrivateKey() {
        return this.wallet.privateKey;
    }
    async signMessage(message) {
        return this.wallet.signMessage(message);
    }
}

// Load an admin wallet with tokens to fund new machine wallets
async function getAdmin() {
    const provider = new ethers.JsonRpcProvider("https://peaq-agung.api.onfinality.io/public"); // Agung testnet
    const adminPrivateKey = "0xADMIN_PRIVATE_KEY"; // Replace securely
    return new Wallet(adminPrivateKey, provider);
}

// Transfer native tokens (gas) to the machine's wallet
async function transferNativeToken(machineWallet, adminWallet) {
    const tx = await adminWallet.sendTransaction({
        to: machineWallet.getAddress(),
        value: ethers.parseEther("1") // Transfer 1 native token
    });

    console.log("Transaction sent:", tx.hash);
    await tx.wait();
    console.log("Transaction confirmed.");
}

// Register a DID Document on the peaq network for the machine
async function generateDID(machineWallet, adminWallet) {
    const HTTPS_BASE_URL = "https://peaq-agung.api.onfinality.io/public";

    const sdk = await Sdk.createInstance({
        baseUrl: HTTPS_BASE_URL,
        chainType: Sdk.ChainType.EVM
    });

    const name = "project_name"; // Customize per project

    const customFields = {
        verifications: [{
            type: "EcdsaSecp256k1RecoveryMethod2020"
        }],
        services: [{
            id: '#admin',
            type: 'admin',
            data: `${adminWallet.address}`
        }]
    };

    const tx = await sdk.did.create({
        name: name,
        address: machineWallet.getAddress(),
        customDocumentFields: customFields
    });

    const receipt = await Sdk.sendEvmTx({
        tx: tx,
        baseUrl: HTTPS_BASE_URL,
        seed: machineWallet.getPrivateKey()
    });

    console.log("peaq DID EVM receipt:\n", receipt);
}


// Main execution flow
async function main() {
    // 1. Create machine wallet
    const machineWallet = new ECDSAKeyring();

    // Optional: store these values securely
    // console.log("Machine Address:", machineWallet.getAddress());
    // console.log("Private Key:", machineWallet.getPrivateKey());

    // 2. Load admin wallet
    const adminWallet = await getAdmin();

    // 3. Transfer tokens to the machine
    await transferNativeToken(machineWallet, adminWallet);

    // 4. Create machine DID Document
    await generateDID(machineWallet, adminWallet);
}

main();

Summary

By running this script, you’ve completed the foundational steps to onboard a machine to the peaq network. Your machine now has a cryptographic identity (via EVM wallet), the necessary native tokens to operate, and a DID Document that serves as its verifiable on-chain identity.

This setup allows your machine to participate securely in decentralized physical infrastructure networks (DePINs), enabling services such as credential validation, data authentication, autonomous task execution, and more.

For production use, always:

  • Store private keys securely (e.g., encrypted storage or secure enclaves).
  • Avoid hardcoding secrets into codebases.
  • Use the peaq mainnet endpoint instead of the agung testnet.

Now that your machine has a verifiable on-chain identity, the next step is to learn how to store and retrieve data using peaq storage — a decentralized storage layer that enables machines to persist important information on-chain.