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

# Spend Permissions via Delegation

> Delegate token spending to a third party with an amount cap. The delegate can transfer tokens on behalf of the owner up to the approved amount, without the owner signing each transaction.

***

Delegation with Light Token works similar to SPL.
When you approve a delegate, you're authorizing a specific account to transfer tokens on your behalf:

* **Owner retains custody**: You still own the tokens and can transfer or revoke at any time. Delegation is non-custodial.
* **Capped spending**: The delegate can spend tokens up to the limit, but cannot access or drain the account beyond the approved amount.
* **Single delegate per account**: Each token account can only have one active delegate. The owner can revoke at any time.
* **New approval replaces old**: Approving a new delegate automatically revokes the previous one

<table>
  <thead>
    <tr>
      <th style={{ width: "15%" }} />

      <th>SPL</th>
      <th>Light</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>**Approve**</td>
      <td>approve()</td>
      <td>approveInterface()</td>
    </tr>

    <tr>
      <td>**Delegated Transfer**</td>
      <td>transfer() (delegate signs)</td>
      <td>transferInterface(..., ownerPubkey, delegateSigner, ...)</td>
    </tr>

    <tr>
      <td>**Revoke**</td>
      <td>revoke()</td>
      <td>revokeInterface()</td>
    </tr>
  </tbody>
</table>

<Accordion title="Agent skill">
  Use the [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments) agent skill to add light-token payment support to your project:

  ```
  npx skills add Lightprotocol/skills
  ```

  For orchestration, install the [general skill](https://zkcompression.com/skill.md):

  ```bash theme={null}
  npx skills add https://zkcompression.com
  ```
</Accordion>

<Tabs>
  <Tab title="Guide">
    ## Use cases

    | Use case               | How delegation helps                                                       |
    | :--------------------- | :------------------------------------------------------------------------- |
    | **Subscriptions**      | Approve a monthly cap. The service provider transfers the fee each period. |
    | **Recurring payments** | Approve a spending limit. The payment processor draws funds as needed.     |
    | **Managed spending**   | A parent or admin approves a cap for a sub-account.                        |
    | **Agent wallets**      | An AI agent operates within a delegated spending limit.                    |

    ## Setup

    <Accordion title="Installation">
      <Tabs>
        <Tab title="npm">
          Install packages in your working directory:

          ```bash theme={null}
          npm install @lightprotocol/stateless.js@^0.23.0 \
                      @lightprotocol/compressed-token@^0.23.0
          ```

          Install the CLI globally:

          ```bash theme={null}
          npm install -g @lightprotocol/zk-compression-cli
          ```
        </Tab>

        <Tab title="yarn">
          Install packages in your working directory:

          ```bash theme={null}
          yarn add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/compressed-token@^0.23.0
          ```

          Install the CLI globally:

          ```bash theme={null}
          yarn global add @lightprotocol/zk-compression-cli
          ```
        </Tab>

        <Tab title="pnpm">
          Install packages in your working directory:

          ```bash theme={null}
          pnpm add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/compressed-token@^0.23.0
          ```

          Install the CLI globally:

          ```bash theme={null}
          pnpm add -g @lightprotocol/zk-compression-cli
          ```
        </Tab>

        <Tab title="SDK 2.0 (token-interface)">
          Install packages in your working directory:

          ```bash theme={null}
          # npm
          npm install @lightprotocol/stateless.js@^0.23.0 \
                      @lightprotocol/token-interface@^0.1.2

          # yarn
          yarn add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/token-interface@^0.1.2

          # pnpm
          pnpm add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/token-interface@^0.1.2
          ```

          Install the CLI globally:

          ```bash theme={null}
          npm install -g @lightprotocol/zk-compression-cli
          ```
        </Tab>
      </Tabs>
    </Accordion>

    <Tabs>
      <Tab title="Localnet">
        ```bash theme={null}
        # start local test-validator in a separate terminal
        light test-validator
        ```

        <Note>
          In the code examples, use `createRpc()` without arguments for localnet.
        </Note>
      </Tab>

      <Tab title="Devnet">
        Get an API key from [Helius](https://helius.dev) and add to `.env`:

        ```bash title=".env" theme={null}
        API_KEY=<your-helius-api-key>
        ```

        <Note>
          In the code examples, use `createRpc(RPC_URL)` with the devnet URL.
        </Note>
      </Tab>
    </Tabs>

    ```typescript theme={null}
    import { createRpc } from "@lightprotocol/stateless.js";

    const rpc = createRpc(RPC_ENDPOINT);
    ```

    ## Approve a delegate

    Grant a delegate permission to spend up to a capped amount:

    ```typescript theme={null}
    import { approveInterface } from "@lightprotocol/compressed-token/unified";

    const tx = await approveInterface(
      rpc,
      payer,
      senderAta,
      mint,
      delegate.publicKey,     // who gets permission
      500_000,                // amount cap
      owner                   // token owner (signs)
    );

    console.log("Approved:", tx);
    ```

    <Accordion title="Compare to SPL">
      ```typescript theme={null}
      import { getApproveCheckedInstruction } from "@solana-program/token";

      const approveInstruction = getApproveCheckedInstruction({
        source: tokenAccountAddress,
        mint: usdcMintAddress,
        delegate: delegateAddress,
        owner: ownerKeypair,
        amount: 1_000_000_000n,
        decimals: 6
      });
      ```
    </Accordion>

    ## Check delegation status

    Check the delegation status of an account:

    ```typescript theme={null}
    import { getAtaInterface } from "@lightprotocol/compressed-token";

    const account = await getAtaInterface(rpc, senderAta, owner.publicKey, mint);

    console.log("Delegate:", account.parsed.delegate?.toBase58() ?? "none");
    console.log("Delegated amount:", account.parsed.delegatedAmount.toString());
    ```

    <Accordion title="Compare to SPL">
      ```typescript theme={null}
      import { fetchToken } from "@solana-program/token";

      const tokenAccount = await fetchToken(rpc, tokenAccountAddress);

      if (tokenAccount.data.delegate) {
        console.log("Delegate:", tokenAccount.data.delegate);
        console.log("Remaining allowance:", tokenAccount.data.delegatedAmount);
      } else {
        console.log("No delegate set");
      }
      ```
    </Accordion>

    ## Transfer as Delegate

    Once approved, the delegate can transfer tokens on behalf of the owner. The delegate is the transaction authority. Only the delegate and fee payer sign; the owner's signature is not required.

    `transferInterface` takes a recipient wallet address and creates the recipient's associated token account internally. For delegated transfers, pass the **source token-account owner** as **`owner`** (pubkey) and the **delegate** as **`authority`** (signer). Do not use removed **`InterfaceOptions.owner`** — there is no `{ owner: ... }` options bag for this flow.

    ```typescript theme={null}
    import { transferInterface } from "@lightprotocol/compressed-token/unified";

    const tx = await transferInterface(
      rpc,
      payer,
      senderAta,
      mint,
      recipient.publicKey,   // recipient wallet (associated token account created internally)
      owner.publicKey,       // source account owner (does not sign)
      delegate,              // delegate authority (signer)
      200_000               // must be within approved cap
    );

    console.log("Delegated transfer:", tx);
    ```

    <Accordion title="Compare to SPL">
      ```typescript theme={null}
      import { getTransferCheckedInstruction } from "@solana-program/token";

      const transferInstruction = getTransferCheckedInstruction({
        source: ownerTokenAccount,
        mint: usdcMintAddress,
        destination: recipientTokenAccount,
        authority: delegateKeypair,
        amount: 100_000_000n,
        decimals: 6
      });
      ```
    </Accordion>

    <Accordion title="Instruction-level builder">
      `createTransferInterfaceInstructions` returns `TransactionInstruction[][]` for manual transaction control. Pass the **token-account owner** pubkey as the flat **`owner`** argument; for delegate-signed transactions, set **`options.delegatePubkey`**.

      ```typescript theme={null}
      import {
        Transaction,
        sendAndConfirmTransaction,
      } from "@solana/web3.js";
      import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified";

      const instructions = await createTransferInterfaceInstructions(
        rpc,
        payer.publicKey,
        mint,
        200_000,
        owner.publicKey,
        recipient.publicKey,
        9, // decimals
        { delegatePubkey: delegate.publicKey }
      );

      for (const ixs of instructions) {
        const tx = new Transaction().add(...ixs);
        await sendAndConfirmTransaction(rpc, tx, [payer, delegate]);
      }
      ```
    </Accordion>

    ## Revoke a delegate

    Remove all spending permissions from the current delegate.
    If you need to reduce the limit, approve the same delegate with a lower amount.

    ```typescript theme={null}
    import { revokeInterface } from "@lightprotocol/compressed-token/unified";

    const tx = await revokeInterface(rpc, payer, senderAta, mint, owner);

    console.log("Revoked:", tx);
    ```

    <Accordion title="Compare to SPL">
      ```typescript theme={null}
      import { getRevokeInstruction } from "@solana-program/token";

      const revokeInstruction = getRevokeInstruction({
        source: tokenAccountAddress,
        owner: ownerKeypair
      });
      ```
    </Accordion>
  </Tab>

  <Tab title="AI Prompt">
    <Prompt description="Integrate light-token APIs for stablecoin payments" actions={["copy", "cursor"]}>
      {`---
            description: Integrate light-token APIs for stablecoin payments
            allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
            ---

            ## Integrate light-token APIs for stablecoin payments

            Context:
            - Guide: https://zkcompression.com/light-token/payments/overview
            - Skills and resources index: https://zkcompression.com/skill.md
            - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison
            - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments
            - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js
            - Import from @lightprotocol/compressed-token/unified for all interface APIs

            SPL → Light Token API mapping:
            | Operation    | SPL                               | Light Token                              |
            | Receive      | getOrCreateAssociatedTokenAccount() | createLoadAtaInstructions() / loadAta()  |
            | Transfer     | createTransferInstruction()        | createTransferInterfaceInstructions()    |
            | Delegated Transfer | transfer() (delegate signs)  | transferInterface(..., ownerPubkey, delegateSigner, ...) |
            | Get Balance  | getAccount()                      | getAtaInterface()                        |
            | Tx History   | getSignaturesForAddress()         | getSignaturesForOwnerInterface()         |
            | Wrap SPL     | N/A                               | createWrapInstruction() / wrap()         |
            | Unwrap       | N/A                               | createUnwrapInstructions() / unwrap()    |

            ### 1. Index project
            - Grep \`@solana/spl-token|@lightprotocol|createTransferInstruction|getAccount|Connection|Keypair|stablecoin|payment\` across src/
            - Glob \`**/*.ts\` and \`**/*.tsx\` for project structure
            - Identify: RPC setup, existing token operations, payment flow, wallet signing pattern
            - Check package.json for existing @lightprotocol/* or @solana/spl-token dependencies
            - Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel

            ### 2. Read references
            - WebFetch the guide above — review Instruction and Action tabs for each operation
            - WebFetch skill.md — check for a dedicated skill and resources matching this task
            - TaskCreate one todo per phase below to track progress

            ### 3. Clarify intention
            - AskUserQuestion: what is the goal? (new payment integration, migrate existing SPL payment flow, add alongside existing SPL)
            - AskUserQuestion: which operations? (receive, send, balance, history, wrap, unwrap — or all)
            - AskUserQuestion: instruction-level API (build your own transactions) or action-level API (high-level, fewer lines)?
            - Summarize findings and wait for user confirmation before implementing

            ### 4. Create plan
            - Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes
            - Verify existing connection/signer setup is compatible (createRpc with ZK Compression endpoint)
            - Key pattern: import from \`@lightprotocol/compressed-token/unified\` for all interface APIs
            - If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion)
            - Present the plan to the user for approval before proceeding

            ### 5. Implement
            - Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js\`
            - Set up RPC: \`createRpc(RPC_ENDPOINT)\` with a ZK Compression endpoint (Helius, Triton)
            - Import from \`@lightprotocol/compressed-token/unified\` for the interface APIs
            - Follow the guide and the approved plan
            - Write/Edit to create or modify files
            - TaskUpdate to mark each step done

            ### 6. Verify
            - Bash \`tsc --noEmit\`
            - Bash run existing test suite if present
            - TaskUpdate to mark complete

            ### Tools
            - mcp__zkcompression__SearchLightProtocol("<query>") for API details
            - mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "<q>") for architecture
            - Task subagent with Grep/Read/WebFetch for parallel lookups
            - TaskList to check remaining work

            ### Resources

            Guides:
            - Basic payment: https://zkcompression.com/light-token/payments/basic-payment
            - Batch payments: https://zkcompression.com/light-token/payments/batch-payments
            - Payment with memo: https://zkcompression.com/light-token/payments/payment-with-memo
            - Receive payments: https://zkcompression.com/light-token/payments/receive-payments
            - Verify payments: https://zkcompression.com/light-token/payments/verify-payments
            - Verify recipient address: https://zkcompression.com/light-token/payments/verify-recipient-address
            - Spend permissions: https://zkcompression.com/light-token/payments/spend-permissions
            - Wrap and unwrap: https://zkcompression.com/light-token/payments/wrap-unwrap
            - Production readiness: https://zkcompression.com/light-token/payments/production-readiness
            - FAQ: https://zkcompression.com/faq
            - Sign with Privy: https://zkcompression.com/light-token/wallets/privy
            - Sign with Wallet Adapter: https://zkcompression.com/light-token/wallets/wallet-adapter
            - Gasless transactions: https://zkcompression.com/light-token/wallets/gasless-transactions

            Examples:
            - All payments: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments
            - Send (instruction): https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/basic-send-instruction.ts
            - Send (action): https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/basic-send-action.ts
            - Batch send: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/batch-send.ts
            - Payment with memo: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/payment-with-memo.ts
            - Receive: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/receive/receive.ts
            - Get balance: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-balance.ts
            - Get history: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-history.ts
            - Verify address: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/verify-address.ts
            - Wrap: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/wrap.ts
            - Unwrap: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/unwrap.ts
            - Privy (Node.js): https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/nodejs
            - Privy (React): https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/react
            - Wallet Adapter (React): https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter/react
            - Gasless transfer: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/gasless-transactions/typescript/gasless-transfer.ts`}
    </Prompt>

    ```text theme={null}
    ---
    description: Integrate light-token APIs for stablecoin payments
    allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
    ---

    ## Integrate light-token APIs for stablecoin payments

    Context:
    - Guide: https://zkcompression.com/light-token/payments/overview
    - Skills and resources index: https://zkcompression.com/skill.md
    - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison
    - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments
    - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js
    - Import from @lightprotocol/compressed-token/unified for all interface APIs

    SPL → Light Token API mapping:
    | Operation    | SPL                               | Light Token                              |
    | Receive      | getOrCreateAssociatedTokenAccount() | createLoadAtaInstructions() / loadAta()  |
    | Transfer     | createTransferInstruction()        | createTransferInterfaceInstructions()    |
    | Delegated Transfer | transfer() (delegate signs)  | transferInterface(..., ownerPubkey, delegateSigner, ...) |
    | Get Balance  | getAccount()                      | getAtaInterface()                        |
    | Tx History   | getSignaturesForAddress()         | getSignaturesForOwnerInterface()         |
    | Wrap SPL     | N/A                               | createWrapInstruction() / wrap()         |
    | Unwrap       | N/A                               | createUnwrapInstructions() / unwrap()    |

    ### 1. Index project
    - Grep `@solana/spl-token|@lightprotocol|createTransferInstruction|getAccount|Connection|Keypair|stablecoin|payment` across src/
    - Glob `**/*.ts` and `**/*.tsx` for project structure
    - Identify: RPC setup, existing token operations, payment flow, wallet signing pattern
    - Check package.json for existing @lightprotocol/* or @solana/spl-token dependencies
    - Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel

    ### 2. Read references
    - WebFetch the guide above — review Instruction and Action tabs for each operation
    - WebFetch skill.md — check for a dedicated skill and resources matching this task
    - TaskCreate one todo per phase below to track progress

    ### 3. Clarify intention
    - AskUserQuestion: what is the goal? (new payment integration, migrate existing SPL payment flow, add alongside existing SPL)
    - AskUserQuestion: which operations? (receive, send, balance, history, wrap, unwrap — or all)
    - AskUserQuestion: instruction-level API (build your own transactions) or action-level API (high-level, fewer lines)?
    - Summarize findings and wait for user confirmation before implementing

    ### 4. Create plan
    - Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes
    - Verify existing connection/signer setup is compatible (createRpc with ZK Compression endpoint)
    - Key pattern: import from `@lightprotocol/compressed-token/unified` for all interface APIs
    - If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion)
    - Present the plan to the user for approval before proceeding

    ### 5. Implement
    - Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js`
    - Set up RPC: `createRpc(RPC_ENDPOINT)` with a ZK Compression endpoint (Helius, Triton)
    - Import from `@lightprotocol/compressed-token/unified` for the interface APIs
    - Follow the guide and the approved plan
    - Write/Edit to create or modify files
    - TaskUpdate to mark each step done

    ### 6. Verify
    - Bash `tsc --noEmit`
    - Bash run existing test suite if present
    - TaskUpdate to mark complete

    ### Tools
    - mcp__zkcompression__SearchLightProtocol("<query>") for API details
    - mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "<q>") for architecture
    - Task subagent with Grep/Read/WebFetch for parallel lookups
    - TaskList to check remaining work

    ### Resources

    Guides:
    - Basic payment: https://zkcompression.com/light-token/payments/basic-payment
    - Batch payments: https://zkcompression.com/light-token/payments/batch-payments
    - Payment with memo: https://zkcompression.com/light-token/payments/payment-with-memo
    - Receive payments: https://zkcompression.com/light-token/payments/receive-payments
    - Verify payments: https://zkcompression.com/light-token/payments/verify-payments
    - Verify recipient address: https://zkcompression.com/light-token/payments/verify-recipient-address
    - Spend permissions: https://zkcompression.com/light-token/payments/spend-permissions
    - Wrap and unwrap: https://zkcompression.com/light-token/payments/wrap-unwrap
    - Production readiness: https://zkcompression.com/light-token/payments/production-readiness
    - FAQ: https://zkcompression.com/faq
    - Sign with Privy: https://zkcompression.com/light-token/wallets/privy
    - Sign with Wallet Adapter: https://zkcompression.com/light-token/wallets/wallet-adapter
    - Gasless transactions: https://zkcompression.com/light-token/wallets/gasless-transactions

    Examples:
    - All payments: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments
    - Send (instruction): https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/basic-send-instruction.ts
    - Send (action): https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/basic-send-action.ts
    - Batch send: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/batch-send.ts
    - Payment with memo: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/payment-with-memo.ts
    - Receive: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/receive/receive.ts
    - Get balance: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-balance.ts
    - Get history: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-history.ts
    - Verify address: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/verify-address.ts
    - Wrap: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/wrap.ts
    - Unwrap: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/unwrap.ts
    - Privy (Node.js): https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/nodejs
    - Privy (React): https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/react
    - Wallet Adapter (React): https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter/react
    - Gasless transfer: https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/gasless-transactions/typescript/gasless-transfer.ts
    ```
  </Tab>
</Tabs>

## Related guides

<CardGroup cols={3}>
  <Card title="Basic payment" icon="arrow-right" href="/light-token/payments/basic-payment">
    Send a single token transfer.
  </Card>

  <Card title="Gasless transactions" icon="hand-holding-dollar" href="/light-token/wallets/gasless-transactions">
    Separate the fee payer from the token owner.
  </Card>

  <Card title="Verify payments" icon="magnifying-glass" href="/light-token/payments/verify-payments">
    Query balances and transaction history.
  </Card>
</CardGroup>

***

## Didn't find what you were looking for?

<Callout type="info">
  Reach out! [Telegram](https://t.me/swen_light) | [email](mailto:support@lightprotocol.com) | [Discord](https://discord.com/invite/7cJ8BhAXhu)
</Callout>
