Skip to main content
Events mode is the cheapest and easiest integration. You keep calling the LLM yourself; you just send PromptWall a copy of each interaction after it happens. PromptWall does not block, rewrite, or enforce anything — it only logs, classifies, and powers the dashboard.

⚡ 30-second integration

Three steps. Each step says exactly where the code goes — terminal or a specific file.
Step 1 — In your terminal, install the SDK:
Terminal
pip install promptwall-sdk
Step 2 — Create a new file test_promptwall.py in any folder. Paste this and replace pk_live_xxxxxxxx with your real key from prompt-wall.com/settings → Apps → + New App → Events:
test_promptwall.py
import os
os.environ["PROMPTWALL_API_KEY"] = "pk_live_xxxxxxxx"   # paste your real key

from promptwall import PromptWall
pw = PromptWall()

# events.send takes a single dict (the event body).
pw.events.send({
    "prompt":            "What is the capital of France?",
    "answer":            "Paris is the capital of France.",
    "model":             "gpt-4o-mini",
    "prompt_tokens":     8,
    "completion_tokens": 6,
})
print("event sent — check the dashboard")
Step 3 — Back in your terminal, run it:
Terminal
python test_promptwall.py
Then open prompt-wall.com/observability — within ~5 seconds you’ll see the event in Recent Traces.Step 4 — Wire into your real LLM call. Open whichever existing file holds your OpenAI / Anthropic call (commonly app.py, services/chat.py, routes/chat.py). Add two lines — one import, one fire-and-forget call after you return the answer to the user:
services/chat.py (your existing file — edit it)
from promptwall import PromptWall                 # ← line 1: import
pw = PromptWall()                                  # singleton

def answer(prompt, user_id):
    completion = openai_client.chat.completions.create(...)   # unchanged
    text = completion.choices[0].message.content
    return_to_user(text)                                       # unchanged

    pw.events.send({                               # ← line 2: log it
        "prompt":            prompt,
        "answer":            text,
        "model":             completion.model,
        "prompt_tokens":     completion.usage.prompt_tokens,
        "completion_tokens": completion.usage.completion_tokens,
        "user_id":           user_id,
    })
The send call is fire-and-forget — it won’t slow your app or break it if PromptWall is unreachable.
Don’t have an API key yet? Sign up at prompt-wall.com/signup (free — $50 of credits), then click + New App in Settings and pick mode Events. Copy the pk_live_… key shown on the final step.
The rest of this page covers user_id / session_id / metadata for richer dashboards, multi-language clients (Go, Ruby, Java, .NET, PHP), and failure-mode handling. Skip ahead only if you need them.

When this mode is right for you

✅ Pick Events when…

  • You need observability + audit trail with zero risk to production latency or behaviour
  • You’re proving compliance / SOC 2 readiness
  • You want to start collecting data before you commit to enforcement
  • Your LLM stack is locked-in (Bedrock, Azure, OpenAI Enterprise) and you can’t insert a proxy

❌ Don't pick Events if…

  • You want PromptWall to block or rewrite unsafe answers — that’s Verify or Full Control
  • You want low-latency pre-flight injection detection — Verify is better
  • You want a single API to call instead of two — Full Control collapses everything into one request
Pricing: $30 per 1,000,000 tokens. No setup fee. Counted from the prompt_tokens + completion_tokens you send us.

What you’ll build

The PromptWall call is fire-and-forget and runs after you’ve already returned the answer. It never blocks your user-visible latency.

Choose your integration

Step 1 — Install the SDK

Run in your project root:
pip install promptwall-sdk
If you use Poetry / uv / Pipenv, run the equivalent. The SDK has zero heavy dependencies (just httpx).

Step 2 — Add API key to your environment

Create new file: .env (in your project root, next to package.json or pyproject.toml). If .env already exists, add the line below. Add .env to .gitignore if it isn’t already.
.env
PROMPTWALL_API_KEY=pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Get the key from prompt-wall.com/settings → Apps tab. Click + New App if you don’t have one yet, choose mode Events, and copy the key shown on the final step (it’s only displayed once).

Step 3 — Create a thin wrapper around your LLM call

Create new file: lib/promptwall_client.py (or wherever you keep shared infrastructure code).
lib/promptwall_client.py
import os
from promptwall import PromptWall

# Singleton — initialise once at module load. The SDK is
# thread-safe and reuses a single connection pool.
_pw = PromptWall(api_key=os.environ["PROMPTWALL_API_KEY"])

def log_interaction(*, prompt: str, answer: str, model: str,
                    prompt_tokens: int, completion_tokens: int,
                    user_id: str | None = None,
                    session_id: str | None = None,
                    metadata: dict | None = None) -> None:
    """Fire-and-forget. Never raises — Events mode is purely
    observability and must not affect production code paths."""
    try:
        _pw.events.send(
            prompt=prompt,
            answer=answer,
            model=model,
            prompt_tokens=prompt_tokens,
            completion_tokens=completion_tokens,
            user_id=user_id,
            session_id=session_id,
            metadata=metadata or {},
        )
    except Exception as exc:
        # Log but don't propagate. Events mode is not in the critical path.
        print(f"[promptwall] events.send failed: {exc}")

Step 4 — Wire into your existing LLM call

Edit existing file: wherever you call OpenAI / Anthropic / etc. Common locations: app.py, main.py, services/chat.py, routes/chat.py. Find the place you receive the LLM response.
Before:
services/chat.py (before)
from openai import OpenAI
client = OpenAI()

def answer(prompt: str, user_id: str) -> str:
    completion = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
    )
    return completion.choices[0].message.content
After (3 lines added):
services/chat.py (after)
from openai import OpenAI
from lib.promptwall_client import log_interaction   # ← added

client = OpenAI()

def answer(prompt: str, user_id: str) -> str:
    completion = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
    )
    text = completion.choices[0].message.content

    log_interaction(                                 # ← added
        prompt=prompt,
        answer=text,
        model=completion.model,
        prompt_tokens=completion.usage.prompt_tokens,
        completion_tokens=completion.usage.completion_tokens,
        user_id=user_id,
    )

    return text
That’s the entire change. Restart the app and the next request triggers an Events call.

Step 5 — Verify it worked

Run a request through your app, then open prompt-wall.com/observability.Within ~5 seconds you should see:
  • Requests counter ticked up
  • A new row in Recent Traces showing your prompt/answer
  • The Events mode counted in the breakdown
Or hit the API directly to confirm:
curl https://api.prompt-wall.com/api/console/requests?limit=1 \
  -H "Authorization: Bearer $PROMPTWALL_JWT"

Step 6 — Deploy to production

Set PROMPTWALL_API_KEY as a secret in your hosting platform:
PlatformWhere to set it
VercelProject → Settings → Environment Variables
RenderService → Environment → Add Environment Variable
Fly.iofly secrets set PROMPTWALL_API_KEY=pk_...
AWS LambdaFunction → Configuration → Environment variables
Herokuheroku config:set PROMPTWALL_API_KEY=pk_...
Railway / Cloudflare WorkersVariables panel in the dashboard
Docker--env flag or docker-compose.yml environment: block
Restart / redeploy after setting it.

Common patterns

Multi-turn conversations

Pass a stable session_id on every event in a single conversation so PromptWall can replay the entire thread on /sessions:
log_interaction(
    prompt=user_message,
    answer=assistant_message,
    model="gpt-4o",
    prompt_tokens=250,
    completion_tokens=80,
    session_id=conversation.id,   # same UUID on every turn
    user_id=current_user.id,
)

Per-environment splitting

Create one App per environment (dev / staging / prod) in Settings → Apps. Each gets its own API key. Use the right key per environment so traces don’t bleed together.
# .env.production
PROMPTWALL_API_KEY=pk_live_prod_xxxxxxxx

# .env.staging
PROMPTWALL_API_KEY=pk_live_stg_yyyyyyyy

Custom metadata for filtering

Anything you put in metadata is searchable in the dashboard:
log_interaction(
    prompt=...,
    answer=...,
    model=...,
    prompt_tokens=...,
    completion_tokens=...,
    metadata={
        "feature": "summarize-pdf",
        "tier":    "enterprise",
        "region":  "eu-west",
        "version": "2.4.1",
    },
)
Then on /traces filter by metadata.feature = "summarize-pdf" to see only those traces.

What you’ll see in the dashboard

Within seconds of your first event:
  • /observability — KPIs (requests, tokens, cost), decisions chart, breakdown table
  • /traces — drill-down on individual prompts + answers
  • /sessions — multi-turn replay (if session_id is set)
  • /billing — credit consumed at $30/M tokens for events
Events traces are flagged with the Events mode badge so they’re easy to distinguish from /v1/verify and /v1/chat traffic.

Next steps

Add Verify mode

Get a real allow/block decision before returning the answer to your user. Same SDK, one extra method call.

Configure policies

Define what counts as PII / brand-safety / off-topic for your tenant. Policies apply across all modes.