juspay/hyperswitch · error

Datatrans requires BodyKey auth type

Error message

Datatrans requires BodyKey auth type

What it means

Hyperswitch's unified connector configuration converts a merchant's `ConnectorAuthType` into the connector-specific auth struct. Datatrans authenticates with credentials carried in the request body (merchant ID + password), so only `ConnectorAuthType::BodyKey` is accepted. Any other auth type produces this error via the catch-all match arm, converting the merchant connector into `Self::Datatrans` fails.

Solutions

  1. Re-configure the Datatrans connector credential with `ConnectorAuthType::BodyKey`, mapping password/api_key to `api_key` and merchant_id to `key1`
  2. Update the connector creation API call so `connector_type`/auth layout matches BodyKey (two fields)
  3. If data was seeded wrongly, migrate existing merchant_connector_credentials rows for Datatrans to the BodyKey shape
  4. Verify with a health/check call for the connector after re-saving credentials

Example fix

// before
ConnectorAuthType::HeaderKey { api_key }
// after
ConnectorAuthType::BodyKey {
    api_key: datatrans_password,
    key1: datatrans_merchant_id,
}
Defensive patterns

Strategy: validation

Validate before calling

fn is_datatrans_auth(auth: &ConnectorAuthType) -> bool {
    matches!(auth, ConnectorAuthType::BodyKey { .. })
}
if !is_datatrans_auth(&auth) {
    return Err(report!(ConfigError::InvalidConnectorAuth("Datatrans requires BodyKey")));
}

Type guard

fn as_body_key(auth: &ConnectorAuthType) -> Option<(&String, &String)> {
    match auth {
        ConnectorAuthType::BodyKey { api_key, key1 } => Some((api_key, key1)),
        _ => None,
    }
}

Try / catch

match build_connector_config(Connector::Datatrans, &auth, metadata) {
    Ok(cfg) => use_config(cfg),
    Err(e) if e.current_context().to_string().contains("BodyKey") => {
        // prompt re-entry of Datatrans credentials as BodyKey
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Configuring the Datatrans connector with `ConnectorAuthType::SignatureKey`, `HeaderKey`, `CertificateKey`, `BodyKey` missing `key1`, or `NoKey`, then attempting a payment or connector-credential conversion in `connector_config.rs`.

Common situations: Merchant selects the wrong auth layout in the connector dashboard/API when adding Datatrans credentials; migration or seed data created credentials as HeaderKey; tenant config scripts pass api_key only without the required second key.

Related errors


AI-assisted analysis of juspay/hyperswitch@afd9284352 (2026-09-18). Data as JSON: /api/errors/83bcf2894279b3b6. Report an issue: GitHub.

Appendix: source

Thrown at crates/router/src/core/unified_connector_service/connector_config.rs:1057

                ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self::Bluesnap {
                    username: key1.clone(),
                    password: api_key.clone(),
                }),
                _ => Err(err("Bluesnap requires BodyKey auth type")),
            },
            Connector::Cryptopay => match auth {
                ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self::Cryptopay {
                    api_key: api_key.clone(),
                    api_secret: key1.clone(),
                }),
                _ => Err(err("Cryptopay requires BodyKey auth type")),
            },
            Connector::Datatrans => match auth {
                ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self::Datatrans {
                    merchant_id: key1.clone(),
                    password: api_key.clone(),
                }),
                _ => Err(err("Datatrans requires BodyKey auth type")),
            },
            Connector::Globalpay => match auth {
                ConnectorAuthType::BodyKey { api_key, key1 } => {
                    let globalpay_meta = metadata
                        .map(|m| {
                            serde_json::from_value::<GlobalpayMetadata>(m.clone())
                                .map_err(|_| err("Invalid Globalpay metadata format"))
                        })
                        .transpose()?;

                    Ok(Self::Globalpay {
                        app_id: key1.clone(),
                        app_key: api_key.clone(),
                        account_name: globalpay_meta.and_then(|m| m.account_name),
                    })
                }
                _ => Err(err("Globalpay requires BodyKey auth type")),
            },

View on GitHub (pinned to afd9284352)