Skip to main content
This guide gets you from zero to working integration in 5 minutes.

Prerequisites

  • Node.js 18+ (or Bun)
  • A user with a Solana wallet
  • An auth token (request one by DMing @beharefe on Telegram or emailing gm@actioncodes.org)
Users generate codes at actioncode.app using their wallet. Your app receives and processes these codes — you don’t need wallet access.

Install the SDK

npm install @actioncodes/sdk

Initialize the client

import { ActionCodesClient } from '@actioncodes/sdk'

const client = new ActionCodesClient({
  authToken: process.env.ACTION_CODES_TOKEN
})
Set your auth token as an environment variable:
export ACTION_CODES_TOKEN="your-auth-token"

Accept a code from a user

When a user wants to interact with your app:
  1. They visit actioncode.app in their wallet browser
  2. They connect their wallet and get an 8-digit code
  3. They share that code with your app
// User provides their code (from actioncode.app)
const code = '48291037'  // example code

// Resolve it to verify and get details
const actionCode = await client.resolve(code)

console.log('Valid code from wallet:', actionCode.pubkey)
console.log('Expires at:', actionCode.expiresAt)

Attach an action

Now attach what you want the user to approve. Choose based on your use case:
import { Transaction, SystemProgram, PublicKey, Connection } from '@solana/web3.js'

// Build your transaction
const connection = new Connection('https://api.mainnet-beta.solana.com')
const { blockhash } = await connection.getLatestBlockhash()

const transaction = new Transaction({
  recentBlockhash: blockhash,
  feePayer: new PublicKey(actionCode.pubkey)
}).add(
  SystemProgram.transfer({
    fromPubkey: new PublicKey(actionCode.pubkey),
    toPubkey: new PublicKey('RecipientAddressHere'),
    lamports: 1_000_000 // 0.001 SOL
  })
)

// Serialize and attach to the code
const serialized = transaction.serialize({
  requireAllSignatures: false
}).toString('base64')

await client.attachTransaction(code, serialized)

Wait for approval

The user will see the pending request in actioncode.app and can approve it with their wallet.
// Watch for the user to approve
for await (const status of client.observeStatus(code)) {
  console.log('Current status:', status.status)

  // Check for transaction signature
  if (status.finalizedSignature) {
    console.log('Transaction signed!')
    console.log('Signature:', status.finalizedSignature)
    break
  }

  // Check for signed message
  if (status.signedMessage) {
    console.log('Message signed!')
    console.log('Signed message:', status.signedMessage)
    break
  }
}

Complete example

Here’s everything together — a simple flow where a user signs a message:
import { ActionCodesClient } from '@actioncodes/sdk'

const client = new ActionCodesClient({
  authToken: process.env.ACTION_CODES_TOKEN
})

async function requestSignature(userCode: string) {
  // 1. Verify the code
  const actionCode = await client.resolve(userCode)
  console.log(`Code valid for wallet: ${actionCode.pubkey}`)

  // 2. Attach a message to sign
  const message = `Verify ownership of ${actionCode.pubkey} at ${Date.now()}`
  await client.attachMessage(userCode, message)
  console.log('Message attached — waiting for user approval...')

  // 3. Wait for signature
  for await (const status of client.observeStatus(userCode)) {
    if (status.signedMessage) {
      console.log('Success! Signed message:', status.signedMessage)
      return status.signedMessage
    }

    // Handle expiry
    if (status.status === 'expired') {
      throw new Error('Code expired before approval')
    }
  }
}

// Usage
const userCode = '48291037' // User provides this from actioncode.app
const signedMessage = await requestSignature(userCode)

User flow summary

1

User gets a code

User opens actioncode.app in their wallet browser (Phantom, Solflare, etc.) and taps “Get Code”
2

User shares the code

User copies the 8-digit code and pastes it into your app
3

Your app attaches an action

You call attachTransaction() or attachMessage()
4

User approves

User sees the request in actioncode.app and taps “Approve” — their wallet signs it
5

Your app gets the result

observeStatus() returns the signature or signed message

Next steps