dhan-rs 0.1.7

Unofficial Rust client library for the DhanHQ Broker API v2 — orders, market data, WebSocket feeds, and more
Documentation
#![allow(missing_docs)]
//! Types for authentication endpoints.

use serde::{Deserialize, Serialize};

// ---------------------------------------------------------------------------
// Token generation / renewal responses
// ---------------------------------------------------------------------------

/// Response from generating or consuming an access token.
///
/// Returned by:
/// - `POST auth.dhan.co/app/generateAccessToken`
/// - `POST auth.dhan.co/app/consumeApp-consent`
/// - `POST auth.dhan.co/partner/consume-consent`
/// - `GET /v2/RenewToken`
#[derive(Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TokenResponse {
    /// User-specific identification generated by Dhan.
    pub dhan_client_id: String,
    /// Name registered on Dhan.
    #[serde(default)]
    pub dhan_client_name: Option<String>,
    /// Unique Client Code registered with Dhan.
    #[serde(default)]
    pub dhan_client_ucc: Option<String>,
    /// DDPI status.
    #[serde(default)]
    pub given_power_of_attorney: Option<bool>,
    /// Generated JWT access token.
    pub access_token: String,
    /// Token expiry time (ISO timestamp, IST).
    #[serde(default)]
    pub expiry_time: Option<String>,
}

impl std::fmt::Debug for TokenResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("TokenResponse")
            .field("dhan_client_id", &self.dhan_client_id)
            .field("dhan_client_name", &self.dhan_client_name)
            .field("dhan_client_ucc", &self.dhan_client_ucc)
            .field("given_power_of_attorney", &self.given_power_of_attorney)
            .field("access_token", &"[REDACTED]")
            .field("expiry_time", &self.expiry_time)
            .finish()
    }
}

// ---------------------------------------------------------------------------
// Individual — API key consent flow
// ---------------------------------------------------------------------------

/// Response from generating an individual API-key consent.
///
/// Returned by `POST auth.dhan.co/app/generate-consent`.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AppConsentResponse {
    /// Temporary session ID for the browser login step.
    pub consent_app_id: String,
    /// Status of the consent request.
    pub consent_app_status: String,
    /// Overall status field.
    #[serde(default)]
    pub status: Option<String>,
}

// ---------------------------------------------------------------------------
// Partner consent flow
// ---------------------------------------------------------------------------

/// Response from generating a partner consent.
///
/// Returned by `POST auth.dhan.co/partner/generate-consent`.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PartnerConsentResponse {
    /// Temporary session ID on the partner level.
    pub consent_id: String,
    /// Status of the consent request.
    pub consent_status: String,
}

// ---------------------------------------------------------------------------
// Static IP management
// ---------------------------------------------------------------------------

/// Request body for setting or modifying a static IP.
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SetIpRequest {
    /// User-specific identification generated by Dhan.
    pub dhan_client_id: String,
    /// Static IP address (IPv4 or IPv6).
    pub ip: String,
    /// Whether this is the primary or secondary IP.
    pub ip_flag: crate::types::IpFlag,
}

/// Response from `GET /v2/ip/getIP`.
///
/// Note: The API returns `primaryIP` / `secondaryIP` (uppercase `IP`),
/// so we use explicit `#[serde(rename)]` instead of `rename_all`.
#[derive(Debug, Clone, Deserialize)]
pub struct IpInfo {
    /// Currently set primary static IP.
    #[serde(default, rename = "primaryIP")]
    pub primary_ip: Option<String>,
    /// Date from which the primary IP can be modified (YYYY-MM-DD).
    #[serde(default, rename = "modifyDatePrimary")]
    pub modify_date_primary: Option<String>,
    /// Currently set secondary static IP.
    #[serde(default, rename = "secondaryIP")]
    pub secondary_ip: Option<String>,
    /// Date from which the secondary IP can be modified (YYYY-MM-DD).
    #[serde(default, rename = "modifyDateSecondary")]
    pub modify_date_secondary: Option<String>,
    /// IP address observed by Dhan for the current request.
    #[serde(default, rename = "detectedIP")]
    pub detected_ip: Option<String>,
    /// Whether the observed address matches a configured address.
    #[serde(default, rename = "ipMatchStatus")]
    pub ip_match_status: Option<IpMatchStatus>,
    /// Whether order placement is allowed for the observed address.
    #[serde(default, rename = "ordersAllowed")]
    pub orders_allowed: Option<bool>,
}

/// Match result returned by `GET /v2/ip/getIP`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[allow(non_camel_case_types)]
pub enum IpMatchStatus {
    PRIMARY_MATCH,
    SECONDARY_MATCH,
    MISMATCH,
    NOT_CONFIGURED,
}

/// Generic success response from set/modify IP.
#[derive(Debug, Clone, Deserialize)]
pub struct IpSetResponse {
    pub message: String,
    pub status: String,
}