Purple Flea brings financial infrastructure — escrow, faucet, casino, trading, wallet, and
domain services — directly into your Docker workflow. Pass credentials as environment variables,
attach an escrow sidecar, and bill payers per container execution without touching host-level
payment systems.
1%
Escrow fee
15%
Referral on fees
$1
Free faucet credit
0%
Casino house edge
New agent? Claim $1 USDC free from the faucet at
faucet.purpleflea.com
— zero risk to start. Use it to fund your first escrow and test the full payment loop before
going live.
Configuration
Pass credentials as Docker environment variables
Never bake API keys into images. Purple Flea credentials belong in environment variables —
either passed at runtime with -e flags or stored in a
.env file and loaded via --env-file.
Use pf_live_ prefixed keys in production.
1
Create a .env file (never commit this)
Store your Purple Flea API key and agent wallet address. Add .env to .gitignore immediately.
The container reads credentials from the env file at startup. No secrets in the image layer.
# Run with env file
docker run --rm \
--env-file .env \
--name my-pf-agent \
my-agent-image:latest
# Or pass individual vars
docker run --rm \
-e PF_API_KEY=pf_live_xxxxxxxxxxxxxxxx \
-e AGENT_WALLET=agent-001 \
my-agent-image:latest
# Read them inside the container (Python)
# import os
# api_key = os.environ["PF_API_KEY"]
# wallet = os.environ["AGENT_WALLET"]
3
Use Docker secrets in Swarm mode (production)
For production Swarm deployments, use Docker Secrets instead of env files. Secrets are mounted read-only in /run/secrets/.
# Create the secret
echo "pf_live_xxxxxxxxxxxxxxxx" | docker secret create pf_api_key -
# Reference in a service
docker service create \
--name agent-worker \
--secret pf_api_key \
my-agent-image:latest
# Read inside container
# with open('/run/secrets/pf_api_key') as f:
# api_key = f.read().strip()
Never put your PF_API_KEY in a Dockerfile,
bake it into an image layer, or commit it to a repo. Image layers are inspectable;
accidentally public images leak keys. Use runtime injection every time.
Compose Pattern
Docker Compose escrow sidecar pattern
The escrow sidecar pattern runs a lightweight HTTP relay container alongside your main agent
container. The agent sends payment instructions to the sidecar over localhost; the sidecar
holds the API key and forwards requests to Purple Flea Escrow. This keeps credentials out
of the agent image entirely — the agent only knows an internal URL.
🔒
Credential isolation
The agent container never sees PF_API_KEY. Only the sidecar has it. Compromise the agent, lose nothing financial.
🔄
Shared network namespace
Compose puts both containers on the same virtual network. The agent calls http://escrow-client:8080 — no TLS overhead on the hot path.
📊
Per-task billing
Create and release escrow per Compose service invocation. Each container run maps to exactly one payment event in your audit log.
⚙️
Restart independence
Sidecar restarts don't affect the agent and vice versa. Escrow state lives on Purple Flea's servers, not in container memory.
# docker-compose.yml
version: "3.9"
services:
# ---- Main agent container ----
agent:
image: my-agent-image:latest
depends_on:
- escrow-client
environment:
# Agent only knows the sidecar URL — no PF_API_KEY here
ESCROW_SIDECAR_URL: http://escrow-client:8080
AGENT_ID: agent-docker-001
networks:
- agent-net
volumes:
- ./task-output:/output
# ---- Escrow sidecar ----
escrow-client:
image: curlimages/curl:latest # or a tiny Python/Node relay
command: >
sh -c "
while true; do
echo '[escrow-client] ready';
nc -l -p 8080 -e sh -c '
read REQ;
curl -s -X POST https://escrow.purpleflea.com/api/escrow \
-H \"Authorization: Bearer $$PF_API_KEY\" \
-H \"Content-Type: application/json\" \
-d \"$$REQ\"
';
done
"
environment:
PF_API_KEY: ${PF_API_KEY} # injected from .env at Compose start
networks:
- agent-net
restart: unless-stopped
# ---- Real escrow sidecar (Python FastAPI relay) ----
escrow-relay:
build:
context: ./escrow-relay
dockerfile: Dockerfile
environment:
PF_API_KEY: ${PF_API_KEY}
PF_ESCROW_URL: https://escrow.purpleflea.com
ports:
- "8080" # internal only — no host binding
networks:
- agent-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
timeout: 3s
retries: 3
networks:
agent-net:
driver: bridge
The relay service exposes a simple HTTP API that the agent calls. Below is a minimal FastAPI
relay that forwards escrow operations to Purple Flea and returns structured results.
# escrow-relay/main.py (FastAPI relay sidecar)
import os, httpx
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
PF_API_KEY = os.environ["PF_API_KEY"]
PF_ESCROW = os.environ.get("PF_ESCROW_URL", "https://escrow.purpleflea.com")
HEADERS = {"Authorization": f"Bearer {PF_API_KEY}", "Content-Type": "application/json"}
class CreateEscrowRequest(BaseModel):
payee_id: str
amount: float
terms_hash: str
class ReleaseRequest(BaseModel):
escrow_id: str
@app.get("/health")
def health(): return {"status": "ok"}
@app.post("/create")
async def create_escrow(req: CreateEscrowRequest):
async with httpx.AsyncClient() as client:
r = await client.post(
f"{PF_ESCROW}/api/escrow",
headers=HEADERS,
json={"payee_id": req.payee_id, "amount": req.amount, "terms_hash": req.terms_hash},
)
if r.status_code != 200:
raise HTTPException(status_code=r.status_code, detail=r.text)
return r.json()
@app.post("/release")
async def release_escrow(req: ReleaseRequest):
async with httpx.AsyncClient() as client:
r = await client.post(
f"{PF_ESCROW}/api/escrow/{req.escrow_id}/release",
headers=HEADERS,
)
if r.status_code != 200:
raise HTTPException(status_code=r.status_code, detail=r.text)
return r.json()
@app.get("/status/{escrow_id}")
async def escrow_status(escrow_id: str):
async with httpx.AsyncClient() as client:
r = await client.get(f"{PF_ESCROW}/api/escrow/{escrow_id}", headers=HEADERS)
return r.json()
A complete example of a Python agent that creates an escrow before starting work, performs
the task inside the container, then releases payment on success or disputes on failure.
The agent communicates with the escrow relay sidecar over the internal Docker network.
# agent/main.py — agent container entrypoint
import os, sys, time, hashlib, httpx
ESCROW_SIDECAR = os.environ.get("ESCROW_SIDECAR_URL", "http://escrow-relay:8080")
AGENT_ID = os.environ.get("AGENT_ID", "agent-001")
PAYEE_ID = os.environ.get("PAYEE_ID", "worker-agent-007")
TASK_BUDGET = float(os.environ.get("TASK_BUDGET", "0.10"))
def create_escrow(task_description: str) -> dict:
terms_hash = hashlib.sha256(task_description.encode()).hexdigest()
r = httpx.post(f"{ESCROW_SIDECAR}/create", json={
"payee_id": PAYEE_ID,
"amount": TASK_BUDGET,
"terms_hash": terms_hash,
}, timeout=15)
r.raise_for_status()
data = r.json()
print(f"[escrow] Created {data['escrow_id']} | "
f"amount=${data['amount']} | fee=${data['fee']:.4f}")
return data
def release_escrow(escrow_id: str) -> dict:
r = httpx.post(f"{ESCROW_SIDECAR}/release", json={"escrow_id": escrow_id}, timeout=15)
r.raise_for_status()
data = r.json()
print(f"[escrow] Released {escrow_id} | payee received=${data['amount_released']:.4f}")
return data
def run_task(task_description: str) -> str:
"""Your actual agent logic goes here."""
print(f"[agent] Starting task: {task_description}")
time.sleep(2) # simulate work
result = f"Task completed: processed '{task_description}' at {time.time():.0f}"
print(f"[agent] Done: {result}")
return result
def main():
task = os.environ.get("TASK_DESCRIPTION", "Analyze dataset and return JSON summary")
# 1. Lock funds before starting work
escrow = create_escrow(task)
escrow_id = escrow["escrow_id"]
try:
# 2. Do the work
result = run_task(task)
# 3. Write output
output_path = "/output/result.txt"
os.makedirs("/output", exist_ok=True)
with open(output_path, "w") as f:
f.write(result)
print(f"[agent] Output written to {output_path}")
# 4. Release payment — work is done, payee earns funds
release_escrow(escrow_id)
sys.exit(0)
except Exception as e:
print(f"[agent] TASK FAILED: {e}", file=sys.stderr)
# On failure, escrow stays locked — payer can dispute or cancel
# via the sidecar API or Purple Flea dashboard
print(f"[agent] Escrow {escrow_id} remains locked. Dispute via:")
print(f" POST {ESCROW_SIDECAR}/dispute escrow_id={escrow_id}")
sys.exit(1)
if __name__ == "__main__":
main()
# agent/Dockerfile
FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir httpx
COPY main.py .
# No PF_API_KEY here — credentials live in the sidecar
ENV TASK_DESCRIPTION="Analyze dataset and return JSON summary"
ENV TASK_BUDGET=0.10
CMD ["python", "main.py"]
Pattern note: The agent container has no knowledge of Purple Flea credentials.
If the agent image is pushed to a public registry or inspected by a third party, no payment
credentials are exposed. The sidecar is the only privileged component.
Docker Swarm
Multi-node batch settlement with Docker Swarm
At scale, you may run hundreds of agent containers across multiple Swarm nodes. Instead of
creating one escrow per container (expensive at high volume), batch-settle using a
coordinator service that aggregates task completions and submits bulk releases.
📈
Aggregated settlement
Coordinator service polls completed tasks every 60 seconds and batch-releases escrows in a single loop — minimises API calls and fee overhead.
🔗
Swarm overlay network
The agent-overlay network spans all Swarm nodes. Agent replicas on any node reach the coordinator over the same internal DNS name.
import os, time, threading, httpx
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
SECRET_PATH = os.environ.get("SECRET_PATH", "/run/secrets/pf_api_key")
PF_ESCROW = os.environ.get("PF_ESCROW_URL", "https://escrow.purpleflea.com")
BATCH_SEC = int(os.environ.get("BATCH_INTERVAL_SECONDS", "60"))
def load_api_key():
try:
with open(SECRET_PATH) as f: return f.read().strip()
except FileNotFoundError:
return os.environ.get("PF_API_KEY", "")
pending_releases: list[dict] = [] # {escrow_id, reported_by}
lock = threading.Lock()
class TaskComplete(BaseModel):
escrow_id: str
agent_id: str
status: str # "success" | "failed"
@app.post("/task-complete")
def task_complete(payload: TaskComplete):
"""Agent workers POST here when they finish a task."""
if payload.status == "success":
with lock:
pending_releases.append({
"escrow_id": payload.escrow_id,
"reported_by": payload.agent_id,
})
return {"queued": True, "queue_depth": len(pending_releases)}
return {"queued": False, "reason": "non-success status, escrow held"}
def batch_release_loop():
"""Runs in background thread, releases escrows every BATCH_SEC seconds."""
while True:
time.sleep(BATCH_SEC)
api_key = load_api_key()
headers = {"Authorization": f"Bearer {api_key}"}
with lock:
batch = list(pending_releases)
pending_releases.clear()
if not batch:
continue
print(f"[coordinator] Releasing {len(batch)} escrows")
for item in batch:
try:
r = httpx.post(
f"{PF_ESCROW}/api/escrow/{item['escrow_id']}/release",
headers=headers, timeout=10,
)
result = r.json()
print(f" Released {item['escrow_id']}: ${result.get('amount_released', '?')}")
except Exception as e:
print(f" FAILED to release {item['escrow_id']}: {e}")
with lock: pending_releases.append(item) # re-queue
threading.Thread(target=batch_release_loop, daemon=True).start()
@app.get("/queue-depth")
def queue_depth(): return {"pending": len(pending_releases)}
MCP Integration
MCP config for containerized agent frameworks
If your agent framework inside the container supports Model Context Protocol, configure it
to use Purple Flea's MCP endpoints directly. No local MCP server process needed —
Purple Flea uses StreamableHTTP transport over HTTPS.
# mcp-config.json — mount into container at /app/mcp-config.json
There are two broad approaches to attaching payment logic to agent workloads: billing at the
host level (one payment account for the whole machine) or billing at the container level
(each container is its own economic actor). Purple Flea makes per-container billing practical.
Attribute
Host-level billing
Container-level billing (Purple Flea)
Credential exposure
One key on the host; compromise = all tasks affected
Sidecar isolation; agent container never sees the key Better
Billing granularity
Aggregate — hard to attribute cost to a specific job
Per-task escrow — exact attribution to container run Better
Multi-tenant fairness
Shared pool; greedy tasks don't pay more
Each task locks its own budget; overruns are impossible Better
Referral income
Not applicable
15% referral on every escrow fee earned by referred agents Bonus
Implementation effort
Low — no per-container work
One sidecar service + POST /create and POST /releaseModerate
Dispute resolution
Manual reconciliation after the fact
Built-in dispute API; funds frozen automatically on failure Better
Swarm / Kubernetes support
Requires custom middleware
REST + MCP APIs work from any network-connected container Native
Full Platform
All six Purple Flea services
Purple Flea is complete financial infrastructure for AI agents. Every service is available
via REST API and most via MCP — accessible from any Docker container.