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

# Delegated Access for EVM Wallets

> Sign messages and transactions on behalf of users using delegated key shares with Dynamic's Python SDK

## Overview

Delegated access allows your server to perform wallet operations on behalf of users with their permission. Dynamic sends delegation credentials to your webhook, and your server uses them to sign without the user being online.

This guide covers the server-side implementation using the Python SDK. For conceptual background on the delegation workflow, see [Delegated Access Overview](/overview/wallets/embedded-wallets/mpc/delegated-access/overview).

## Prerequisites

* A Dynamic environment with embedded wallets (MPC) enabled
* Server API key from the [Dynamic Dashboard](/overview/developer-dashboard/tokens-api-keys)
* [Delegated access configured](/overview/wallets/embedded-wallets/mpc/delegated-access/configuration)

## How Delegation Works

1. User approves delegation in your application (client-side)
2. Dynamic sends delegation credentials to your webhook:
   * `walletId` — the user's wallet ID
   * `encryptedWalletApiKey` — temporary API key, encrypted with your RSA public key
   * `encryptedDelegatedShare` — the server key share, encrypted with your RSA public key
3. Your server decrypts the credentials and stores them securely
4. Your server uses the credentials to sign on the user's behalf

## Step 1: Decrypt the Webhook Payload

Dynamic encrypts delegation credentials with your RSA public key. Decrypt them before use:

```python theme={"system"}
from dynamic_wallet_sdk.delegated.decrypt import decrypt_delegated_webhook_data

# webhook_body is the parsed JSON from Dynamic's webhook POST
decrypted = decrypt_delegated_webhook_data(
    private_key_pem=your_rsa_private_key_pem,  # str or bytes
    encrypted_delegated_key_share=webhook_body["encryptedDelegatedShare"],
    encrypted_wallet_api_key=webhook_body["encryptedWalletApiKey"],
)

wallet_api_key = decrypted.decrypted_wallet_api_key
key_share = decrypted.decrypted_delegated_share["secretShare"]
```

Store `wallet_api_key` and `key_share` encrypted in your database alongside the `walletId`.

## Step 2: Create a Delegated Client

`create_delegated_evm_client` returns a fully authenticated `DynamicEvmWalletClient` — no follow-up `authenticate_api_token` call is needed.

```python theme={"system"}
from dynamic_wallet_sdk.delegated.client import create_delegated_evm_client

client = await create_delegated_evm_client(
    environment_id="your-environment-id",
    api_key="your-server-api-key",
)
```

## Step 3: Sign a Message

`delegated_sign_message` for EVM returns a signature object exposing `r`, `s`, and `v` byte components. Most EVM tooling expects the standard `0x`-prefixed 132-character `r || s || v` hex string, so convert it before passing the signature downstream.

```python theme={"system"}
from dynamic_wallet_sdk.delegated.client import delegated_sign_message

sig_obj = await delegated_sign_message(
    client,
    wallet_id="wallet-id-from-webhook",
    wallet_api_key=wallet_api_key,
    key_share=key_share,
    message="0x...",   # hex-encoded keccak256 hash of the message
    chain_name="EVM",
    is_formatted=True,
)

signature_hex = "0x" + sig_obj.r.hex() + sig_obj.s.hex() + format(sig_obj.v, "02x")
print(f"Signature: {signature_hex}")
```

**`is_formatted`:**

* `True` — `message` is already the 32-byte keccak256 hash (hex)
* `False` — `message` is plain text; the SDK applies EIP-191 prefixing and hashing for you

## Complete Webhook Handler Example

```python theme={"system"}
import os
from dynamic_wallet_sdk.delegated.client import create_delegated_evm_client, delegated_sign_message
from dynamic_wallet_sdk.delegated.decrypt import decrypt_delegated_webhook_data

RSA_PRIVATE_KEY = os.environ["RSA_PRIVATE_KEY_PEM"]

async def handle_delegation_webhook(webhook_body: dict):
    """Store delegation credentials received from Dynamic."""
    decrypted = decrypt_delegated_webhook_data(
        private_key_pem=RSA_PRIVATE_KEY,
        encrypted_delegated_key_share=webhook_body["encryptedDelegatedShare"],
        encrypted_wallet_api_key=webhook_body["encryptedWalletApiKey"],
    )

    # Store encrypted in your database
    await db.store_delegation(
        wallet_id=webhook_body["walletId"],
        wallet_api_key=encrypt(decrypted.decrypted_wallet_api_key),
        key_share=encrypt(decrypted.decrypted_delegated_share["secretShare"]),
    )


async def sign_on_behalf_of_user(wallet_id: str, message_hash: str) -> str:
    """Sign using stored delegation credentials."""
    credentials = await db.get_delegation(wallet_id)

    client = await create_delegated_evm_client(
        environment_id=os.environ["DYNAMIC_ENV_ID"],
        api_key=os.environ["DYNAMIC_API_KEY"],
    )

    sig_obj = await delegated_sign_message(
        client,
        wallet_id=wallet_id,
        wallet_api_key=decrypt(credentials.wallet_api_key),
        key_share=decrypt(credentials.key_share),
        message=message_hash,
        chain_name="EVM",
        is_formatted=True,
    )

    return "0x" + sig_obj.r.hex() + sig_obj.s.hex() + format(sig_obj.v, "02x")
```

## Security Considerations

* **Never log** delegation credentials (wallet API key, key share)
* Store credentials **encrypted at rest** — treat them like passwords
* Use **secure environment variables** for your RSA private key and server API key
* The RSA private key used for decryption should never leave your server

## Next Steps

* [Sign messages](/python/evm/sign-messages)
* [Sign transactions](/python/evm/sign-transactions)
* [Create SVM wallet](/python/svm/create-wallet)
