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

# SDK Methods

> Complete reference for @actioncodes/sdk

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @actioncodes/sdk
  ```

  ```bash pnpm theme={null}
  pnpm add @actioncodes/sdk
  ```

  ```bash yarn theme={null}
  yarn add @actioncodes/sdk
  ```
</CodeGroup>

## Initialize

```typescript theme={null}
import { ActionCodesClient } from '@actioncodes/sdk'

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

<Warning>
  **Auth token required.** Request one by DMing [@beharefe](https://t.me/beharefe) on Telegram or emailing [gm@actioncodes.org](mailto:gm@actioncodes.org).
</Warning>

***

## Methods

### resolve

Verify a code and get its details.

```typescript theme={null}
const actionCode = await client.resolve(code)
```

<ParamField path="code" type="string" required>
  The 8-digit action code from the user
</ParamField>

<ResponseField name="ActionCode">
  <Expandable title="Properties">
    <ResponseField name="code" type="string">
      The 8-digit code
    </ResponseField>

    <ResponseField name="pubkey" type="string">
      The wallet public key this code belongs to
    </ResponseField>

    <ResponseField name="expiresAt" type="number">
      Unix timestamp when the code expires
    </ResponseField>

    <ResponseField name="status" type="string">
      Current status: `pending`, `attached`, `finalized`, or `expired`
    </ResponseField>
  </Expandable>
</ResponseField>

**Example:**

```typescript theme={null}
const actionCode = await client.resolve('48291037')

console.log('Wallet:', actionCode.pubkey)
console.log('Expires:', new Date(actionCode.expiresAt))
console.log('Status:', actionCode.status)
```

***

### getStatus

Get the current status of a code.

```typescript theme={null}
const status = await client.getStatus(code)
```

<ParamField path="code" type="string" required>
  The action code to check
</ParamField>

<ResponseField name="ActionCodeStatusResponse">
  <Expandable title="Properties">
    <ResponseField name="status" type="string">
      `pending` | `attached` | `finalized` | `expired`
    </ResponseField>

    <ResponseField name="expiresAt" type="number">
      Unix timestamp
    </ResponseField>

    <ResponseField name="hasTransaction" type="boolean">
      Whether a transaction is attached
    </ResponseField>

    <ResponseField name="hasMessage" type="boolean">
      Whether a message is attached
    </ResponseField>

    <ResponseField name="finalizedSignature" type="string | undefined">
      Transaction signature (if finalized with transaction)
    </ResponseField>

    <ResponseField name="signedMessage" type="string | undefined">
      Signed message bytes (if finalized with message)
    </ResponseField>
  </Expandable>
</ResponseField>

**Example:**

```typescript theme={null}
const status = await client.getStatus('48291037')

if (status.finalizedSignature) {
  console.log('Transaction signed:', status.finalizedSignature)
}
```

***

### observeStatus

Watch for status changes over time. Returns an async iterator.

```typescript theme={null}
for await (const status of client.observeStatus(code, options)) {
  // Handle status updates
}
```

<ParamField path="code" type="string" required>
  The action code to observe
</ParamField>

<ParamField path="options" type="object">
  <Expandable title="Properties">
    <ParamField path="interval" type="number" default="2000">
      Polling interval in milliseconds
    </ParamField>

    <ParamField path="timeout" type="number" default="120000">
      Maximum time to observe in milliseconds
    </ParamField>
  </Expandable>
</ParamField>

**Example:**

```typescript theme={null}
for await (const status of client.observeStatus('48291037', { interval: 1000 })) {
  console.log('Status:', status.status)

  if (status.finalizedSignature) {
    console.log('Done! Signature:', status.finalizedSignature)
    break
  }

  if (status.signedMessage) {
    console.log('Done! Signed message:', status.signedMessage)
    break
  }

  if (status.status === 'expired') {
    console.log('Code expired')
    break
  }
}
```

<Tip>
  `observeStatus` automatically stops when the code is finalized or expires. You can also `break` early.
</Tip>

***

### attachTransaction

Attach a transaction for the user to sign.

```typescript theme={null}
await client.attachTransaction(code, transaction, meta?)
```

<ParamField path="code" type="string" required>
  The action code
</ParamField>

<ParamField path="transaction" type="string" required>
  Base64-encoded serialized transaction
</ParamField>

<ParamField path="meta" type="ActionCodeMeta">
  Optional metadata (description, label, etc.)
</ParamField>

**Example:**

```typescript theme={null}
import { Transaction, SystemProgram, PublicKey, Connection } from '@solana/web3.js'

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

const tx = new Transaction({
  recentBlockhash: blockhash,
  feePayer: new PublicKey(actionCode.pubkey)
}).add(
  SystemProgram.transfer({
    fromPubkey: new PublicKey(actionCode.pubkey),
    toPubkey: new PublicKey(recipient),
    lamports: amount
  })
)

// Serialize (without signatures) and attach
const serialized = tx.serialize({ requireAllSignatures: false }).toString('base64')

await client.attachTransaction(code, serialized, {
  description: 'Transfer 0.1 SOL'
})
```

***

### attachMessage

Attach a message for the user to sign.

```typescript theme={null}
await client.attachMessage(code, message, meta?)
```

<ParamField path="code" type="string" required>
  The action code
</ParamField>

<ParamField path="message" type="string" required>
  The message to sign
</ParamField>

<ParamField path="meta" type="ActionCodeMeta">
  Optional metadata
</ParamField>

**Example:**

```typescript theme={null}
await client.attachMessage(code, 'Sign in to MyApp at ' + Date.now(), {
  description: 'Sign-in verification'
})
```

***

### finalizeTransaction

Manually finalize a code with a transaction signature. Usually not needed — the user's wallet does this automatically.

```typescript theme={null}
await client.finalizeTransaction(code, signature)
```

<ParamField path="code" type="string" required>
  The action code
</ParamField>

<ParamField path="signature" type="string" required>
  The transaction signature
</ParamField>

***

### finalizeMessage

Manually finalize a code with a signed message. Usually not needed — the user's wallet does this automatically.

```typescript theme={null}
await client.finalizeMessage(code, signedMessage)
```

<ParamField path="code" type="string" required>
  The action code
</ParamField>

<ParamField path="signedMessage" type="string" required>
  The signed message
</ParamField>

***

### register

Create a new action code. **For advanced use** — most apps receive codes from users instead.

```typescript theme={null}
const actionCode = await client.register(pubkey, sign, metadata?)
```

<ParamField path="pubkey" type="PublicKey" required>
  The wallet public key
</ParamField>

<ParamField path="sign" type="function" required>
  A function that signs a message: `(message: string) => Promise<string>`
</ParamField>

<ParamField path="metadata" type="ActionCodeMeta">
  Optional metadata
</ParamField>

**Example:**

```typescript theme={null}
import { PublicKey } from '@solana/web3.js'

const actionCode = await client.register(
  new PublicKey(walletAddress),
  async (message) => {
    // Sign with your wallet
    return wallet.signMessage(message)
  },
  { description: 'My action code' }
)

console.log('Generated code:', actionCode.code)
```

<Warning>
  Most applications should **receive** codes from users rather than generate them. Users generate codes at [actioncode.app](https://actioncode.app).
</Warning>

***

## Error Handling

The SDK throws specific error types:

```typescript theme={null}
import {
  CodeNotFoundError,
  ExpiredCodeError,
  InvalidCodeFormatError,
  UnauthorizedError
} from '@actioncodes/sdk'

try {
  await client.resolve(code)
} catch (error) {
  if (error instanceof CodeNotFoundError) {
    console.log('Code does not exist')
  } else if (error instanceof ExpiredCodeError) {
    console.log('Code has expired')
  } else if (error instanceof InvalidCodeFormatError) {
    console.log('Invalid code format (must be 8 digits)')
  }
}
```

| Error                    | Cause                                   |
| ------------------------ | --------------------------------------- |
| `CodeNotFoundError`      | The code doesn't exist                  |
| `ExpiredCodeError`       | The code has expired (\~2 min lifetime) |
| `InvalidCodeFormatError` | Code is not 8 digits                    |
| `UnauthorizedError`      | Permission denied                       |

***

## Types

### ActionCodeMeta

```typescript theme={null}
interface ActionCodeMeta {
  description?: string  // Human-readable description
  label?: string        // Short label
  memo?: string         // Additional memo
}
```

### ActionCodeStatusResponse

```typescript theme={null}
interface ActionCodeStatusResponse {
  status: 'pending' | 'attached' | 'finalized' | 'expired'
  expiresAt: number
  hasTransaction: boolean
  hasMessage: boolean
  finalizedSignature?: string
  signedMessage?: string
}
```

### ObserveStatusOptions

```typescript theme={null}
interface ObserveStatusOptions {
  interval?: number   // Polling interval in ms (default: 2000)
  timeout?: number    // Max observation time in ms (default: 120000)
}
```
