Kevo Docs

Delegations

Allow your backend to sign transactions on behalf of users, with policy controls over chains, contracts, values, and time windows.

How it works

A delegation authorizes Kevo to accept backend-initiated sign requests for a user after that user opts in. Unlike the old browser-share model, granting a delegation does not upload wallet material from the iframe.

1. User grants delegation

The user calls grantDelegation() from your app. Kevo stores delegation metadata and policy constraints for that project-scoped user.

2. Backend signs through KevoAdmin

Your backend calls admin.delegations.signEvm() or admin.delegations.signSolana(). Kevo checks policies first, then routes the request through the server-side signing path.

3. User can revoke at any time

Calling revokeDelegation() invalidates future backend sign requests immediately.

Each user can have at most one active delegation per project at a time. Calling grantDelegation() again replaces the previous delegation and its policies.

Granting a delegation

React hook

typescript
import { useKevo } from '@kevo-ws/sdk/react'

function DelegationButton() {
  const { grantDelegation, getDelegation, revokeDelegation } = useKevo()

  async function handleGrant() {
    const delegation = await grantDelegation({
      include: 'both',
      policies: {
        expiresAt: '2026-12-31T00:00:00.000Z',
        maxTxCount: 200,
        allowedChainIds: [8453, 1],
        allowedContracts: ['0xYourContract...'],
        maxAmountWei: '1000000000000000000',
      },
    })
    console.log('Delegation active, txCount:', delegation.txCount)
  }

  return (
    <div>
      <button onClick={handleGrant}>Enable auto-signing</button>
      <button onClick={() => getDelegation().then(console.log)}>Check status</button>
      <button onClick={revokeDelegation}>Revoke</button>
    </div>
  )
}
Delegations authorize server-side signing for future backend requests. Treat them as a privileged capability and scope them tightly with policies.

Direct client call (without React)

typescript
import { KevoClient } from '@kevo-ws/sdk'

const client = new KevoClient({ publishableKey: 'pk_live_...' })

const delegation = await client.grantDelegation({
  include: 'evm',
  policies: { maxTxCount: 50 },
})

const current = await client.getDelegation()
await client.revokeDelegation()

Client-side REST endpoints

GET/v1/wallets/me/delegationBearer (user)

Returns the current user's active delegation, or null.

POST/v1/wallets/me/delegation/grantBearer (user)

Grant or replace a delegation.

http
POST /v1/wallets/me/delegation/grant
Authorization: Bearer <user_access_token>
Content-Type: application/json

{
  "include": "both",
  "policies": {
    "expiresAt": "2026-12-31T00:00:00.000Z",
    "maxTxCount": 500
  }
}
DELETE/v1/wallets/me/delegation/revokeBearer (user)

Revoke the active delegation permanently.

Delegation policies

typescript
interface GrantDelegationOptions {
  include?: 'evm' | 'solana' | 'both'
  policies?: {
    expiresAt?: string
    maxTxCount?: number
    allowedChainIds?: number[]
    allowedContracts?: string[]
    maxAmountWei?: string
  }
}
FieldTypeDescription
expiresAtISO 8601 stringHard expiry. Signing attempts after this datetime return 403.
maxTxCountnumberMax successful signatures allowed.
allowedChainIdsnumber[]EVM chain ID whitelist. Enforced when chainId is provided.
allowedContractsstring[]EVM contract address whitelist, case-insensitive.
maxAmountWeidecimal stringMax native value per EVM transaction in wei.

Security notes

No browser wallet-material upload

The delegation flow no longer depends on extracting wallet material from the iframe.

Policy checks before signing

Chain, contract, amount, count, and expiry checks run before the signer is reached.

Metadata-only responses

Delegation list and detail endpoints return policy metadata, never raw wallet material.