Python SDK
Fetch managed prompts and report run telemetry — without your code ever crashing if the service is unreachable.
Install
pip install promptflipRequires Python 3.10 or newer. One runtime dependency: httpx.
Quickstart
from promptflip import PromptFlip
pm = PromptFlip(api_key="sk_...", environment="prod")
# Fetch a prompt. Always returns a usable Prompt — never throws.
prompt = pm.get(
"support-agent-system",
fallback="You are a helpful support agent for [[plan]]-plan users.",
inputs={"plan": user.plan},
assignment_key=user.id, # sticky A/B variant
)
# Use it with your model, report telemetry in one block:
with prompt.run() as r:
response = call_your_model(prompt.text)
r.tokens = response.total_tokens
r.converted = True # any attribute name -> custom metric
# Or report metrics directly (inline, or from a worker later):
pm.send(prompt, csat_score=5)Your API key decides which prompts getsees: a key fetches prompts from the workspace it belongs to — a key created in a workspace serves that workspace's prompts; a personal key serves your personal workspace.
The three primitives
That is the entire surface a caller writes against. version pins a fetch to a specific published version instead of always resolving the live one — useful for testing an older version deliberately.
pm.get(key, fallback, *, inputs=None, assignment_key=None, version=None) -> Prompt
pm.send(prompt_or_id, **metrics)
with prompt.run() as r: ...Guarantees
- Never throws on the serving path.
getalways returns aPrompt;sendalways returns. A missingapi_keydoes not raise either — it selects local-only mode (see below). Construction only raises if you pass the private test-only transport hook outsideENV=test. - Hybrid, local-first resolution.
getresolves in order: cloud (a live fetch whenapi_keyis set — served from the disk cache first if it's fresh, or its last-known cached value — memory, then disk, even if stale — the instant the live call fails or errors) → local repo (iflocal_diris set — the same files the CLI manages) → yourfallbackstring → empty, with a warning. In other words: a cached cloud value always wins over local files and the fallback, even when the network is down. EveryPromptexposes which tier resolved it viaprompt.source("cloud","local","fallback", or"none"). - Caching. An in-memory LRU cache holds the last-seen value per key with no expiry (evicted only by size, capped by
cache_max_size) — this is what backs the last-known fallback above. Passcache_dirto also persist a cross-process disk cache with a TTL (cache_ttl, default 300 seconds) and stale-while-revalidate — a stale entry is served immediately while a fresh one is fetched in the background. - One runtime dependency:
httpx.
Error handling
The SDK never throws on the serving path. Failures emit structured WARNING logs to the promptflip logger; attach a handler to react:
import logging
class CreditAlert(logging.Handler):
def emit(self, record):
if getattr(record, "kind", None) == "out_of_credits":
alert("PromptFlip out of credits")
logging.getLogger("promptflip").addHandler(CreditAlert())Records carry a structured kind, one of: transport, out_of_credits, quota_exceeded, missing_inputs, missing_vars, missing_variables, missing_inputs_in_fallback, invalid_metric, not_found, unresolved, unknown.
Fallback templates
A fallback uses the same [[placeholders]] syntax as the stored prompt; the SDK fills them client-side from inputs so online and offline render identically. Check a fallback in your tests:
from promptflip import check_fallback
missing = check_fallback("Hello [[name]] on [[plan]]", inputs={"name": "Alice"})
# missing == ["plan"]