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

# Rust SDK development

> Architecture and usage patterns for the DFNS Rust SDK, including client configuration, user action signing, API domains, delegated signing, and error handling.

## Request signing

All state-changing requests made to the DFNS API must be cryptographically signed. `DfnsClient` handles the challenge flow automatically when you configure a signer: it calls `/auth/action/init`, hands you the challenge, and replays your assertion on the real request.

<Info>
  For a detailed explanation of request signing and User Action Challenges, see [Signing requests](/guides/developers/signing-requests).
</Info>

## Client configuration

Both `DfnsClient` and `DfnsDelegatedClient` take the same `Options`:

```rust theme={null}
use dfns_sdk_rust::{DfnsClient, Options};

let client = DfnsClient::new(Options {
    base_url: String::new(),
    auth_token: "your-auth-token".to_string(),
    signer: None,
    http: None,
})?;
```

| Field | Description |
| - | - |
| `base_url` | DFNS API base URL. An empty string defaults to `https://api.dfns.io`. |
| `auth_token` | Service Account token, Personal Access Token, or user login token. See [Required headers](/api-reference/auth). |
| `signer` | `Option<Arc<dyn UserActionSigner>>`. Required for state-changing operations on `DfnsClient`, unused by `DfnsDelegatedClient`. |
| `http` | `Option<reqwest::Client>` to reuse your own HTTP client (connection pool, proxy, timeouts). |

## Implementing a signer

The SDK does not ship a key signer. It defines the `UserActionSigner` trait and leaves the credential-specific crypto to you, so the same client works with a raw key, an HSM, or a KMS:

```rust theme={null}
use async_trait::async_trait;
use dfns_sdk_rust::error::Error;
use dfns_sdk_rust::signer::{
    CredentialAssertion, CredentialAssertionData, UserActionChallenge, UserActionSigner,
};

struct MyKeySigner {
    cred_id: String,
    // private key material, HSM handle, KMS client, ...
}

#[async_trait]
impl UserActionSigner for MyKeySigner {
    async fn sign(&self, challenge: &UserActionChallenge) -> Result<CredentialAssertion, Error> {
        // 1. Build the clientData JSON for `challenge.challenge` and base64url-encode it.
        // 2. Sign the clientData bytes with your credential's private key.
        // 3. Return the assertion, with the signature base64url-encoded.
        Ok(CredentialAssertion {
            kind: "Key".to_string(),
            credential_assertion: CredentialAssertionData {
                cred_id: self.cred_id.clone(),
                client_data: client_data_base64url,
                signature: signature_base64url,
            },
        })
    }
}
```

| Field | Description |
| - | - |
| `kind` | `"Key"` for key credentials (Service Accounts, Personal Access Tokens), `"Fido2"` for passkeys. |
| `cred_id` | ID of the credential registered with your token. Find it in the DFNS Dashboard under `Settings` > `Service Accounts` or `Settings` > `Personal Access Tokens`. |
| `client_data` | Base64url-encoded `clientData` JSON built from the challenge. |
| `signature` | Base64url-encoded signature over the `clientData` bytes. |

<Warning>
  The exact `clientData` shape and stringification rules are defined in [Credentials data](/api-reference/auth/credentials-data#key-password-protected-key-and-recovery-credential). Incorrect stringification causes `Unable to verify signature` errors.
</Warning>

Calling a state-changing method without a configured signer returns `Error::SignerRequired`.

## Available API domains

The client provides typed access to all DFNS API domains:

| Domain | Description |
| - | - |
| `client.wallets` | Wallet creation, listing, and management |
| `client.keys` | Key management operations |
| `client.policies` | Policy rules and approvals |
| `client.permissions` | Access control and permissions |
| `client.webhooks` | Webhook subscriptions |
| `client.signers` | Signer management |
| `client.staking` | Staking operations |
| `client.networks` | Network information |
| `client.exchanges` | Exchange integrations |
| `client.fee_sponsors` | Fee sponsorship |
| `client.swaps` | Token swap operations |
| `client.vaults` | Vault operations |
| `client.payins` | Payin operations |
| `client.payouts` | Payout operations |
| `client.allocations` | Allocation management |
| `client.address_watches` | Address watch operations |
| `client.agreements` | Agreement management |
| `client.auth` | Authentication and user management |

## Delegated signing

`DfnsDelegatedClient` exposes the same domains, but every operation that requires a user action signature is split into two methods:

| Method | Returns |
| - | - |
| `<operation>_init(body)` | The `UserActionChallenge` to be signed by the end user |
| `<operation>_complete(body, challenge_identifier, assertion)` | The operation result |

Read-only methods are identical on both clients. See [Delegated wallets](/guides/developers/delegated-wallets) for a full implementation guide.

## Error handling

All methods return `Result<T, dfns_sdk_rust::Error>`:

```rust theme={null}
use dfns_sdk_rust::Error;

match client.wallets.get_wallet("invalid-wallet-id".to_string()).await {
    Ok(wallet) => println!("Wallet: {}", wallet.id),
    Err(Error::Api { status, body }) => {
        eprintln!("API error (status {}): {}", status, body.message);
    }
    Err(err) => eprintln!("Error: {}", err),
}
```

| Variant | Cause |
| - | - |
| `Api { status, body }` | Non-2xx response with a decodable DFNS error body |
| `ApiRaw { status, raw }` | Non-2xx response with an undecodable body |
| `Config(String)` | Invalid base URL or auth token |
| `SignerRequired` | A signed operation was issued without a signer |
| `Signer(String)` | Your `UserActionSigner` implementation failed |
| `Transport(reqwest::Error)` | Connection, timeout, or other transport failure |
| `Serde(serde_json::Error)` | Request or response (de)serialization failure |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.