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

# Managing Secrets with Python SDK

> How to manage secrets using the Julep Python SDK

# Managing Secrets with Python SDK

This guide covers how to manage secrets using the Julep Python SDK. Secrets allow you to securely store and use sensitive information like API keys, passwords, and access tokens in your Julep applications.

## Installation

Ensure you have the latest version of the Python SDK:

```bash theme={"dark"}
pip install julep
```

## Authentication

Initialize the client with your API key:

```python theme={"dark"}
from julep import Julep

client = Julep(api_key="your_api_key")
```

## Creating Secrets

Create a new secret:

```python theme={"dark"}
secret = client.secrets.create(
    name="stripe_api_key",
    value="sk_test_...",
    description="Stripe API key for payment processing",
    metadata={"environment": "production", "owner": "payments-team"}
)

print(f"Created secret: {secret.name}")
```

### Required Parameters

* `name`: The name of the secret (must be a valid identifier)
* `value`: The secret value to encrypt and store

### Optional Parameters

* `description`: A description of what the secret is used for
* `metadata`: A dictionary of metadata to associate with the secret

## Listing Secrets

List all available secrets:

```python theme={"dark"}
# List all secrets
secrets = client.secrets.list()
for secret in secrets.items:
    print(f"{secret.name}: {secret.description}")
```

### Pagination

Use pagination to handle large numbers of secrets:

```python theme={"dark"}
# List with pagination
secrets_page_1 = client.secrets.list(limit=10, offset=0)
secrets_page_2 = client.secrets.list(limit=10, offset=10)
```

### Filtering by Metadata

Filter secrets based on metadata:

```python theme={"dark"}
# Filter by metadata
production_secrets = client.secrets.list(
    metadata={"environment": "production"}
)

# Filter by multiple metadata fields
team_secrets = client.secrets.list(
    metadata={
        "environment": "production",
        "owner": "payments-team"
    }
)
```

## Retrieving Secrets

Get a specific secret by name:

```python theme={"dark"}
secret = client.secrets.get(name="stripe_api_key")
print(f"Secret: {secret.name}, Created: {secret.created_at}")

# Access the secret value
print(f"Secret value: {secret.value}")
```

> **Note**: For security, when listing secrets, the `.value` field will always show "ENCRYPTED". The actual secret value is only returned when specifically requesting a single secret by name.

## Updating Secrets

Update an existing secret:

```python theme={"dark"}
updated_secret = client.secrets.update(
    name="stripe_api_key",
    value="sk_test_new_value...",
    description="Updated Stripe API key",
    metadata={"environment": "production", "owner": "payments-team", "rotated": "2025-05-10"}
)

print(f"Updated secret: {updated_secret.name}")
```

### Partial Updates

You can update specific fields without changing others:

```python theme={"dark"}
# Update only the description
updated_secret = client.secrets.update(
    name="stripe_api_key",
    description="New description for Stripe API key"
)

# Update only the metadata
updated_secret = client.secrets.update(
    name="stripe_api_key",
    metadata={"last_rotated": "2025-05-10"}
)
```

## Deleting Secrets

Delete a secret when it's no longer needed:

```python theme={"dark"}
client.secrets.delete(name="stripe_api_key")
print("Secret deleted")
```

## Using Secrets in Tasks

Reference secrets when executing tasks:

```python [expandable] theme={"dark"}
from julep import Julep

client = Julep(api_key="your_api_key")

# Define a task that uses a secret
task_definition = {
    "steps": [
        {
            "kind": "tool_call",
            "tool": "openai",
            "operation": "chat",
            "arguments": {
                "model": "gpt-4",
                "messages": [
                    {"role": "user", "content": "What's the weather like?"}
                ]
            },
            "secret_name": "openai_api_key"
        }
    ]
}

# Create and execute the task
task = client.tasks.create(task=task_definition)
execution = client.tasks.execute(task_id=task.id)
```

### Using Secrets in Expressions

You can reference secrets in expressions:

```python theme={"dark"}
task_definition = {
    "steps": [
        {
            "kind": "transform",
            "expression": "$ f'https://api.example.com/v1?api_key={secrets.api_key}&query={input}'",
            "input": "search query",
            "output": "api_url"
        }
    ]
}
```

### Using Multiple Secrets

For tools that require multiple secrets:

```python theme={"dark"}
task_definition = {
    "steps": [
        {
            "kind": "tool_call",
            "tool": "database",
            "operation": "query",
            "arguments": {
                "query": "SELECT * FROM users",
                "connection": {
                    "host": "$ secrets.db_host",
                    "user": "$ secrets.db_username",
                    "password": "$ secrets.db_password",
                    "database": "$ secrets.db_name"
                }
            }
        }
    ]
}
```

## Error Handling

Handle common errors when working with secrets:

```python [expandable] theme={"dark"}
from julep.exceptions import (
    SecretNotFoundError,
    SecretAlreadyExistsError,
    ValidationError
)

try:
    secret = client.secrets.get(name="non_existent_secret")
except SecretNotFoundError:
    print("Secret not found")

try:
    # Attempt to create a secret with an invalid name
    secret = client.secrets.create(name="invalid name", value="test")
except ValidationError as e:
    print(f"Validation error: {e}")

try:
    # Attempt to create a duplicate secret
    secret = client.secrets.create(name="existing_secret", value="test")
except SecretAlreadyExistsError:
    print("Secret already exists")
```

## Secret Rotation Example

Implement a secret rotation policy:

```python [expandable] theme={"dark"}
import uuid
from datetime import datetime

def rotate_secret(client, secret_name, new_value):
    """
    Safely rotate a secret by creating a new one and verifying it works
    before deleting the old one.
    """
    # Create a temporary secret with a random suffix
    temp_name = f"{secret_name}_rotation_{uuid.uuid4().hex[:8]}"
    
    # Create the new secret
    client.secrets.create(
        name=temp_name,
        value=new_value,
        description=f"Temporary rotation for {secret_name}",
        metadata={"rotation_date": datetime.now().isoformat()}
    )
    
    # Here you would test that the new secret works
    # ...
    
    # If tests pass, update metadata on the old secret
    old_secret = client.secrets.get(name=secret_name)
    old_metadata = old_secret.metadata or {}
    old_metadata.update({
        "archived": "true",
        "replaced_by": temp_name,
        "archived_date": datetime.now().isoformat()
    })
    
    client.secrets.update(
        name=secret_name,
        metadata=old_metadata
    )
    
    # Rename the temporary secret to the standard name
    client.secrets.delete(name=secret_name)
    client.secrets.update(
        name=temp_name,
        new_name=secret_name,
        description=old_secret.description,
        metadata={"last_rotated": datetime.now().isoformat()}
    )
    
    return client.secrets.get(name=secret_name)

# Example usage
new_key = "sk_test_new_value_after_rotation"
rotated_secret = rotate_secret(client, "stripe_api_key", new_key)
print(f"Rotated secret: {rotated_secret.name}")
```

## Best Practices

1. Use a consistent naming convention for all secrets
2. Add detailed descriptions and metadata to make secrets discoverable
3. Implement a rotation policy for sensitive secrets
4. Log secret operations (creation, updates, deletions) but never log values
5. Use try/except blocks to handle potential errors gracefully
6. Consider automating secret rotation for important credentials
7. Use metadata to track important dates and ownership information

## Next Steps

* [Common Secrets Patterns](/sdks/common/secrets) - Patterns that work across all SDKs
* [Secrets Management](/advanced/secrets-management) - Advanced guide for managing secrets
* [Using Secrets in Julep](/guides/using-secrets) - Step-by-step guide for using secrets
