from nekuda import NekudaClientclient = NekudaClient(api_key="sk_live_your_api_key", # Replace with your actual secret API key # base_url="https://api.nekuda.ai", # Default, usually not neededtimeout=30, # Optional: request timeout in secondsmax_retries=3, # Optional: max retries for retryable errors (429, 5xx)backoff_factor=0.5, # Optional: backoff factor for retries)
The base URL for the nekuda API. Defaults to production. Only change this for
staging/testing (e.g., https://staging-api.nekuda.ai) or if using a mock
server. The SDK normalizes this URL.
Factory method to create a NekudaClient instance configured from environment variables.
Copy
from nekuda import NekudaClient# Reads NEKUDA_API_KEY for the API key.# Reads NEKUDA_BASE_URL (optional) for the base URL, defaults to https://api.nekuda.ai.# Allows overriding other client parameters too.client = NekudaClient.from_env( # api_key_var="CUSTOM_API_KEY_ENV_VAR_NAME", # Default: "NEKUDA_API_KEY" # base_url_var="CUSTOM_BASE_URL_ENV_VAR_NAME", # Default: "NEKUDA_BASE_URL" timeout=45 # Example: override default timeout)
This is the recommended way to initialize the client for most applications.
Creates a UserContext for a specific user. This context automatically includes the user_id in subsequent API calls made through it. A user_id is a mandatory string that uniquely identifies your end-user.
Copy
from nekuda import NekudaClientclient = NekudaClient.from_env()user_identifier = "unique_user_abc_123"user_context = client.user(user_identifier)# Now use methods on user_context:# mandate_response = user_context.create_mandate(...)# reveal_token_response = user_context.request_card_reveal_token(...)# card_details = user_context.reveal_card_details(...)
Using UserContext is preferred over passing user_id to each client method directly.
Note: It is recommended to use user_context.create_mandate(mandate_data, ...) instead.
Creates a purchase mandate (intent to buy) for a given user. This is a required first step before a card reveal token can be requested. The user_id must be provided.
Copy
from nekuda import NekudaClient, MandateDataclient = NekudaClient.from_env()user_identifier = "user_for_mandate_creation"mandate_info = MandateData( product="Deluxe Widget", price=199.99, currency="USD", merchant="My Test Shop")# Optional idempotency key for safe retries of this specific request# custom_request_id = "my_unique_mandate_request_001"try: response = client.create_mandate( user_id=user_identifier, mandate_data=mandate_info, # request_id=custom_request_id ) print(f"Mandate Created: {response.mandate_id} for user: {user_identifier}") # The response.mandate_id is then used for request_card_reveal_tokenexcept NekudaError as e: print(f"Error creating mandate: {e}")
Note: It is recommended to use user_context.request_card_reveal_token(mandate_id) instead.
Requests a one-time, short-lived token to reveal card details for a specific mandate. A mandate must have been successfully created first to obtain a mandate_id. The user_id must match the one used for mandate creation.
Copy
from nekuda import NekudaClientclient = NekudaClient.from_env()user_identifier = "user_for_token_request"existing_mandate_id = 12345 # Obtained from a previous create_mandate calltry: response = client.request_card_reveal_token( user_id=user_identifier, mandate_id=existing_mandate_id ) print(f"Reveal Token: {response.reveal_token} for user: {user_identifier}") # This response.reveal_token is then used for reveal_card_detailsexcept NekudaError as e: print(f"Error requesting reveal token: {e}")
Note: It is recommended to use user_context.reveal_card_details(reveal_token) instead.
Reveals actual card details using a valid reveal_token obtained from request_card_reveal_token. The user_id must match.
Copy
from nekuda import NekudaClientclient = NekudaClient.from_env()user_identifier = "user_for_card_reveal"valid_reveal_token = "rvl_tok_from_previous_step"try: card = client.reveal_card_details( user_id=user_identifier, reveal_token=valid_reveal_token ) print(f"Card Number (last 4): {card.card_number[-4:]} for user: {user_identifier}") print(f"Card Expiry: {card.card_expiry_date}")except NekudaError as e: print(f"Error revealing card details: {e}")
A convenience wrapper returned by client.user(user_id) that automatically includes the user_id in all its API calls. This is the recommended way to interact with user-specific endpoints.
Copy
from nekuda import NekudaClient, MandateDataclient = NekudaClient.from_env()user_context = client.user("unique_user_id_789")# Example mandate creation using UserContextmandate_details = MandateData( product="Super Plan", price=29.00, currency="EUR", merchant="My Service")try: mandate_response = user_context.create_mandate(mandate_details) print(f"Mandate ID from UserContext: {mandate_response.mandate_id}") # Request reveal token using UserContext and the new mandate_id reveal_token_response = user_context.request_card_reveal_token(mandate_response.mandate_id) print(f"Reveal Token from UserContext: {reveal_token_response.reveal_token[:10]}...") # Reveal card details using UserContext and the new token card_object = user_context.reveal_card_details(reveal_token_response.reveal_token) print(f"Cardholder via UserContext: {card_object.cardholder_name}")except NekudaError as e: print(f"UserContext operation failed: {e}")
The UserContext object has the following methods, which mirror the client methods but without requiring user_id as a parameter:
Represents the user’s intent to purchase. This data is sent when creating a mandate. It includes built-in Pydantic validation.
Copy
from nekuda import MandateData, NekudaValidationErrortry: mandate = MandateData( # Required fields product="Premium Subscription", # Name of the product/service price=49.99, # Price (must be > 0) currency="USD", # 3-letter ISO currency code # Optional fields merchant="Your Company LLC", # Your merchant name displayed to user merchant_link="https://yourcompany.com/premium", # Link to product/merchant product_description="Monthly access to all premium features and support.", confidence_score=0.95, # Your system's confidence (0.0 to 1.0) that this is a legitimate user intent # request_id: Optional[str] = None # Auto-generated UUID if not provided for create_mandate idempotency )except NekudaValidationError as e: print(f"Invalid MandateData: {e}")
All nekuda SDK API methods return typed Pydantic models with automatic validation.
Response from create_mandate() or user_context.create_mandate().
Copy
class MandateCreateResponse: mandate_id: int # Unique ID for the created mandate request_id: str # Request tracking ID (idempotency key used or generated) customer_id: str # The user_id you provided for this mandate created_at: datetime # Timestamp of mandate creation (UTC) updated_at: Optional[datetime] # Timestamp of last update (UTC), if any
Response from create_mandate() or user_context.create_mandate().
Copy
class MandateCreateResponse: mandate_id: int # Unique ID for the created mandate request_id: str # Request tracking ID (idempotency key used or generated) customer_id: str # The user_id you provided for this mandate created_at: datetime # Timestamp of mandate creation (UTC) updated_at: Optional[datetime] # Timestamp of last update (UTC), if any
Response from request_card_reveal_token() or user_context.request_card_reveal_token().
Copy
class CardRevealTokenResponse: reveal_token: str # The single-use token for revealing card details reveal_path: str # API endpoint path where this token can be used (for info only) expires_at: Optional[datetime] # Timestamp when this token expires (UTC), if applicable
Response from reveal_card_details() or user_context.reveal_card_details().
Copy
class CardDetailsResponse: # Required fields card_number: str # Full card number (PAN). Validated by SDK to be 13-19 digits. card_expiry_date: str # Expiry date in MM/YY format. Validated by SDK. cardholder_name: str # Name on the card as collected. # Optional fields (availability depends on what was collected/stored) last4_digits: Optional[str] # Last 4 digits of the card number. email: Optional[str] # Email address associated with the card/user. billing_address: Optional[str] # Billing address lines. zip_code: Optional[str] # Billing address ZIP or postal code. phone_number: Optional[str] # Phone number associated.
Validation by SDK:
card_number is validated to be a string of 13-19 digits.
card_expiry_date is validated to be in MM/YY format and represent a plausible future date.
All exceptions raised by the nekuda SDK inherit from a base NekudaError class.
Refer to the Error Handling guide for a detailed hierarchy and usage patterns.
This example shows the an end-to-end flow: creating a client, getting a user context, creating a mandate, requesting a reveal token, and revealing card details.
Copy
from nekuda import NekudaClient, MandateData, NekudaErrorimport os # For environment variables# Best practice: Initialize client from environment variables# Ensure NEKUDA_API_KEY is set in your environment.# NEKUDA_BASE_URL defaults to https://api.nekuda.ai if not set.client = NekudaClient.from_env()# Each of your users must have a unique identifier string.user_identifier = "example_user_e2e_flow_001"user = client.user(user_identifier)try: # Step 1: Create a mandate (intent to purchase) print(f"Creating mandate for user '{user_identifier}'...") mandate_payload = MandateData( product="Ultimate Gadget X", price=299.99, currency="USD", merchant="Future Tech Inc.", product_description="The latest and greatest gadget with all new features." ) mandate_resp = user.create_mandate(mandate_payload) print(f"✅ Mandate created successfully! ID: {mandate_resp.mandate_id}") # Step 2: Request a card reveal token using the mandate_id from Step 1 print(f"Requesting card reveal token for mandate ID '{mandate_resp.mandate_id}'...") reveal_token_resp = user.request_card_reveal_token( mandate_id=mandate_resp.mandate_id ) print(f"🔑 Reveal token received: {reveal_token_resp.reveal_token[:15]}...") # Step 3: Reveal the actual card details using the token from Step 2 print(f"Revealing card details with token...") card_details = user.reveal_card_details(reveal_token_resp.reveal_token) # Now you have the card details to use with your payment processor print(f"💳 Card details revealed for user '{user_identifier}':") print(f" Card Number: **** **** **** {card_details.card_number[-4:]}") # Only print last 4 for security print(f" Expiry Date: {card_details.card_expiry_date}") print(f" Cardholder Name: {card_details.cardholder_name}") print("🎉 Full flow completed successfully!")except CardNotFoundError as e: print(f"Card Not Found for user '{e.user_id}': {e.message}") print("This often means payment details were not collected or user_id mismatch.")except InvalidRequestError as e: print(f"Invalid Request: {e.message} (Code: {e.code}, HTTP Status: {e.status_code})") print("Check your parameters, like mandate_id format or if it exists.")except AuthenticationError as e: print(f"Authentication Failed: {e.message}. Check your NEKUDA_API_KEY.")except NekudaValidationError as e: print(f"Data Validation Error: {e}. This could be an issue with data sent or received.")except NekudaApiError as e: print(f"nekuda API Error: {e.message} (Code: {e.code}, HTTP Status: {e.status_code})")except NekudaError as e: # Catch any other Nekuda SDK-specific errors print(f"A nekuda SDK error occurred: {e}")except Exception as e: # Fallback for unexpected errors print(f"An unexpected error occurred: {e}")
For simpler scripts or applications where dependency injection is overkill.
Copy
from nekuda import set_default_client, get_default_client, NekudaClient, MandateData# Set once at startup (e.g., in your main script or app initialization)set_default_client(NekudaClient.from_env()) # Configured from environmentdef some_business_logic_function(user_id: str, product_details: dict): client_instance = get_default_client() # Retrieve the globally set client user_context = client_instance.user(user_id) mandate_info = MandateData( product=product_details["name"], price=product_details["price"], currency=product_details["currency"], merchant="Global Client Store" ) try: mandate_response = user_context.create_mandate(mandate_info) # ... continue with reveal token and card details ... print(f"Mandate {mandate_response.mandate_id} created via global client for {user_id}") except NekudaError as e: print(f"Error in business logic with global client: {e}")# Example call# some_business_logic_function("user_global_client_test", {"name": "Test Product", "price": 1.00, "currency": "USD"})
While convenient, the global client pattern can make it harder to manage
configurations and test components in isolation in larger applications. Use
with discretion.