TagwiseTagwiseDevnet
Integration Guides

Registering a Tag

Build a complete non-custodial tag registration flow in your application.

Registering a tag on TIP creates a permanent Program Derived Address (PDA) on the Solana blockchain. Because TIP is non-custodial, the API constructs an unsigned transaction which the connected wallet signs and broadcasts.


Registration Workflow

1. Authenticate (SIWS) ──> 2. Call register({ tag }) ──> 3. Wallet Signs & Broadcasts

Registration can be self-paid or sponsored:

  • Self-paid (default): the connected owner's wallet pays the account rent and network fee. Only the owner needs to sign.
  • Sponsored: pass feePayer to have a separate sponsor wallet cover rent and fees instead, so a user with no SOL can still claim a tag. Because Solana's fee payer is baked into the signed message, this must be decided when the transaction is built, so a sponsored transaction needs signatures from both the owner and the sponsor before it can be submitted.

Complete Code Example

import { TipClient } from "@tagwise/tip-sdk";

async function registerUserTag(client: TipClient, walletAdapter: any, desiredTag: string) {
  // Step 1: Ensure client is authenticated via SIWS
  if (!client.token) {
    await client.connect({
      publicKey: walletAdapter.publicKey.toBase58(),
      signMessage: async (bytes) => walletAdapter.signMessage(bytes),
    });
  }

  // Step 2: Request unsigned register_tag transaction
  const unsignedRes = await client.register({
    tag: desiredTag,
    wallet: walletAdapter.publicKey.toBase58(), // Optional: defaults to owner pubkey
  });

  console.log("Unsigned Base64 Transaction:", unsignedRes.transaction);
  console.log("Derived Tag PDA:", unsignedRes.pda);

  // Step 3: Sign & Submit via SDK or Wallet Adapter
  // Option A: Use SDK convenience method (requires rpcUrl in TipClient)
  const txSignature = await client.signAndSendTransaction(
    unsignedRes.transaction,
    walletAdapter
  );

  console.log("Tag registered! Transaction Signature:", txSignature);
  return txSignature;
}

// sponsorWallet covers rent and fees; the connected wallet is still
// recorded as the tag's owner.
const unsignedRes = await client.register({
  tag: desiredTag,
  feePayer: sponsorWallet.publicKey.toBase58(),
});

// Both wallets must sign the same unsigned transaction bytes, in either
// order, before it can be submitted.
const partiallySignedByOwner = await ownerWallet.signTransaction(unsignedRes.transaction);
const fullySigned = await sponsorWallet.signTransaction(partiallySignedByOwner);

Ownership Is Unaffected

feePayer only decides who pays. The owner recorded on the tag is always the authenticated wallet from the SIWS session, never the sponsor.


Important Constraints & Errors

Rent Exemption Fee

Whichever wallet pays (the owner by default, or feePayer when sponsored) must hold a minimum SOL balance (approx 0.002 SOL) to cover the network fee and the PDA account's rent-exempt deposit. If that wallet's balance is insufficient, the API responds with a 402 before any transaction is built.

Handling Specific Errors

import {
  TagInvalidError,
  ForbiddenError,
  RateLimitedError,
  NoSessionError,
} from "@tagwise/tip-sdk";

try {
  await client.register({ tag: "alice" });
} catch (error) {
  if (error instanceof TagInvalidError) {
    console.error("Tag is malformed, profanity-blocked, or already taken.");
  } else if (error instanceof NoSessionError) {
    console.error("Must call client.connect() before registering.");
  } else if (error instanceof RateLimitedError) {
    console.error("Too many registration requests. Please wait.");
  }
}

On this page