Before jumping into advanced usage, itโ€™s worth getting familiar with the building blocks that form the nekuda SDK public surface.

NekudaClient

The single entry-point to all network operations that:
  • Manages an internal persistent HTTP client with automatic retry & back-off for 5xx / 429 responses
  • Can be instantiated directly or via the convenience constructor from environment variables
  • Automatically normalizes URLs (adds https://, removes trailing slashes). The default base URL is https://api.nekuda.ai
from nekuda import NekudaClient

# Production client
client = NekudaClient(api_key="sk_live_...")

# Client pointing to a different API endpoint (e.g. staging)
# client = NekudaClient(api_key="sk_test_...", base_url="https://staging-api.nekuda.ai")

UserContext

A lightweight wrapper returned by client.user(user_id) that automatically injects the user_id header on every call. A user_id is mandatory for all user-specific operations like creating mandates or revealing cards.
from nekuda import NekudaClient, MandateData

client = NekudaClient.from_env()

# You must provide a unique user_id for each of your users.
user_id = "user_unique_identifier_123"
user = client.user(user_id)

# Example MandateData (details below)
mandate_details = MandateData(
    product="Example Product",
    price=10.99,
    currency="USD",
    merchant="YourStore"
)

# The user_id is now automatically included in the following calls:
# 1. Create a mandate (intent to purchase)
mandate_response = user.create_mandate(mandate_details)

# 2. A mandate must be created first to obtain a mandate_id.
# This mandate_id is then used to request a card reveal token.
reveal_response = user.request_card_reveal_token(mandate_response.mandate_id)

# 3. Exchange the token for card details
card_details_response = user.reveal_card_details(reveal_response.reveal_token)
Behind the scenes no extra network round-trip happens for client.user(user_id) โ€“ UserContext is just a convenience object that stores the user_id.

MandateData

A data class that represents the userโ€™s intent to purchase. It must be successfully submitted via user.create_mandate(mandate_data) to obtain a mandate_id before you can request a card reveal token.
from nekuda import MandateData

mandate = MandateData(
    product="Premium Subscription",
    price=49.99,
    currency="USD",
    merchant="nekuda Corp",
    # Optional fields:
    merchant_link="https://app.nekuda.ai/premium",
    product_description="Access to all premium features",
    confidence_score=0.95
)
Client-side validation runs in __post_init__. Invalid payloads raise NekudaValidationError before any HTTP request is made.

Response Models ๐ŸŽฏ

All API methods return strongly-typed response models. This provides:
  • Type safety - Your IDE knows exactly what fields are available
  • Validation - Card numbers, expiry dates, etc. are automatically validated
  • Better errors - Clear messages when API returns unexpected data

Key Response Models

Example with Type Safety

# user_id had to be passed in each call
token_dict = client.request_card_reveal_token(user_id="some_user", mandate_id="m_123")
token = token_dict["reveal_token"]  # ๐Ÿ˜Ÿ Hope the key exists!

Error Hierarchy

All exceptions inherit from a common NekudaError base class so a single error handler can catch everything:
NekudaError
 โ”œโ”€ NekudaApiError
 โ”‚   โ”œโ”€ AuthenticationError     # 401
 โ”‚   โ”œโ”€ InvalidRequestError     # 4xx / 404
 โ”‚   โ”œโ”€ CardNotFoundError       # 404 (specific case)
 โ”‚   โ”œโ”€ RateLimitError          # 429 (retry-able)
 โ”‚   โ””โ”€ ServerError             # 5xx (retry-able)
 โ”œโ”€ NekudaConnectionError       # network issues
 โ””โ”€ NekudaValidationError       # client-side validation failed
The SDK detects and properly handles HTML error pages (nginx errors, gateway timeouts) that sometimes occur during infrastructure issues.
For a deep-dive see the dedicated Error Handling page.

Advanced Features ๐Ÿš€

Response Validation

The SDK automatically validates all API responses:

URL Normalization

The default base URL is https://api.nekuda.ai. You generally donโ€™t need to set this unless using a staging or mock server.
# Client uses https://api.nekuda.ai by default
client_prod = NekudaClient(api_key="sk_live_...")

# Example for staging (if needed)
# client_staging = NekudaClient(api_key="sk_test_...", base_url="https://staging-api.nekuda.ai")

Performance & Re-usability

The SDK client is designed to be cheap to instantiate but you can (and should) reuse a single instance across the lifetime of your process for maximum performance. Internally it lazily creates the underlying HTTP session the first time you make a request.

Thread-safety

NekudaClient is thread-safe and can be shared across threads.

Future Roadmap

Async Support Coming Soon ๐Ÿ”ฎ The public API has been designed with parity in mind, so an AsyncNekudaClient will drop in without breaking changes.

Whatโ€™s Next?