API Reference

Complete API documentation for the Redenv Python SDK.

ClassDescription
RedenvAsync client for loading and writing secrets
RedenvSyncSynchronous client for scripts and legacy apps
SecretsContainer returned by load() with helper methods
RedenvErrorCustom error class with error codes

Redenv Class (Async)#

The async client for interacting with Redenv. Uses asyncio and requires await for all operations.

Constructor#

from redenv import Redenv

redenv = Redenv(options: dict)

Options

PropertyTypeRequiredDefaultDescription
projectstrYesProject name
token_idstrYesService Token public ID (stk_...)
tokenstrYesService Token secret key (redenv_sk_...)
upstash.urlstrYesUpstash Redis REST URL
upstash.tokenstrYesUpstash Redis REST token
environmentstrNo"development"Environment name
cache.ttlintNo300Seconds before cache is stale
cache.swrintNo86400Stale-while-revalidate window (seconds)
env.overrideboolNoTrueOverwrite existing os.environ vars
logstrNo"low"Logging verbosity ("none", "low", "high")

init()#

Initialize the client, populate os.environ, and return secrets for validation.

async def init() -> Secrets
secrets = await redenv.init()
secrets.require("DATABASE_URL")  # Validate at startup

load()#

Fetch, decrypt, cache, and return secrets.

async def load() -> Secrets
secrets = await redenv.load()
print(secrets["API_KEY"])

Info

init() and load() are identical. Use init() at startup, load() everywhere else for semantic clarity.


set()#

Add or update a secret.

async def set(key: str, value: str) -> None
ParameterTypeDescription
keystrSecret key name
valuestrSecret value
await redenv.set("LOG_LEVEL", "debug")

get_version()#

Fetch a specific version of a secret (time travel).

async def get_version(
    key: str,
    version: int,
    mode: Literal["id", "index"] = "id"
) -> Optional[str]
ParameterTypeDefaultDescription
keystrSecret key name
versionintVersion ID or index
mode"id" | "index""id"Lookup mode
# By version ID
v5 = await redenv.get_version("API_KEY", 5)

# By index (0 = latest, 1 = previous, ...)
previous = await redenv.get_version("API_KEY", 1, "index")

RedenvSync Class#

The synchronous client for scripts and legacy applications. All methods are blocking.

Constructor#

from redenv import RedenvSync

redenv = RedenvSync(options: dict)

Options are identical to the async Redenv class.


init()#

def init() -> Secrets
secrets = redenv.init()
secrets.require("DATABASE_URL")

load()#

def load() -> Secrets
secrets = redenv.load()
print(secrets["API_KEY"])

set()#

def set(key: str, value: str) -> None
redenv.set("LOG_LEVEL", "debug")

get_version()#

def get_version(
    key: str,
    version: int,
    mode: Literal["id", "index"] = "id"
) -> Optional[str]
# By version ID
v5 = redenv.get_version("API_KEY", 5)

# By index (0 = latest, 1 = previous, ...)
previous = redenv.get_version("API_KEY", 1, "index")

Secrets Class#

Returned by load() and init(). Extends Python's dict with enhanced access to secrets.

Dict Access#

Access secrets directly via dictionary syntax:

secrets = redenv.load()

secrets["API_KEY"]       # str
secrets["DATABASE_URL"]  # str
secrets.get("MY-KEY")    # str | None

get()#

Get a secret with optional default value and type-casting.

def get(
    key: str,
    default: Any = None,
    cast: Optional[Type | Callable] = None
) -> Any
ParameterTypeDefaultDescription
keystrSecret key name
defaultAnyNoneDefault if key missing or cast fails
castType | CallableNoneType to cast value to
secrets.get("PORT", 3000, cast=int)    # int
secrets.get("DEBUG", False, cast=bool) # bool
secrets.get("CONFIG", {}, cast=dict)   # dict (parsed JSON)
secrets.get("HOSTS", [], cast=list)    # list (parsed JSON)

Supported casts:

  • int - Parse as integer
  • float - Parse as float
  • bool - Parse as boolean ("true", "1", "yes", "on"True)
  • dict - Parse as JSON object
  • list - Parse as JSON array
  • Any callable - Custom parser

require()#

Validate that secrets exist. Throws RedenvError if any are missing.

def require(*keys: str) -> Secrets
secrets.require("DATABASE_URL", "JWT_SECRET", "STRIPE_KEY")
# Throws: RedenvError: [SECRET_NOT_FOUND] Missing required secrets: JWT_SECRET

Returns self for chaining:

db_url = secrets.require("DATABASE_URL")["DATABASE_URL"]

scope()#

Create a subset with only prefixed keys (prefix is removed).

def scope(prefix: str) -> Secrets
# Secrets: AWS_ACCESS_KEY, AWS_SECRET_KEY, AWS_REGION, OTHER_VAR

aws = secrets.scope("AWS_")
aws["ACCESS_KEY"]  # AWS_ACCESS_KEY value
aws["SECRET_KEY"]  # AWS_SECRET_KEY value
aws["REGION"]      # AWS_REGION value
# OTHER_VAR not included

raw#

Access unexpanded values (with ${VAR} syntax preserved).

@property
def raw() -> Secrets
# If AUTH_URL = "${BASE_URL}/auth"

secrets["AUTH_URL"]      # "https://api.example.com/auth"
secrets.raw["AUTH_URL"]  # "${BASE_URL}/auth"

items()#

Iterate over key-value pairs.

def items() -> ItemsView[str, str]
for key, value in secrets.items():
    print(f"{key}: {value}")

keys() / values()#

Standard dict methods for iteration.

list(secrets.keys())    # ["API_KEY", "DATABASE_URL", ...]
list(secrets.values())  # ["sk_...", "postgres://...", ...]

__repr__() / __str__()#

Masked string representation (safe for logging).

print(secrets)
# Secrets({'API_KEY': '********', 'DATABASE_URL': '********'})

RedenvError#

Custom error class for Redenv-specific errors.

from redenv import RedenvError

class RedenvError(Exception):
    code: str
    message: str

Error Codes#

CodeDescription
MISSING_CONFIGRequired configuration options missing
PROJECT_NOT_FOUNDProject doesn't exist in Redis
INVALID_TOKEN_IDService Token ID not found
INVALID_TOKENService Token secret key invalid
SECRET_NOT_FOUNDRequested secret key doesn't exist
DECRYPTION_FAILEDFailed to decrypt (wrong password/token)
INVALID_INPUTInvalid input to method (e.g., empty key)
UNKNOWN_ERRORUnexpected error

Example#

from redenv import RedenvError

try:
    secrets = redenv.load()
    secrets.require("MISSING_KEY")
except RedenvError as e:
    print(f"[{e.code}] {e.message}")
    # [SECRET_NOT_FOUND] Missing required secrets: MISSING_KEY