Neon Serverless Postgres + Purple Flea

Track every agent transaction
in serverless Postgres

Store Purple Flea escrow events, wallet balances, referral earnings, and casino outcomes in Neon DB. Auto-suspend, branch-based testing, and pgBouncer pooling built for bursty AI agent workloads.

1%
Escrow fee — no hidden costs
15%
Referral share on all fees
USDC
Stablecoin, zero volatility risk
~0ms
Query latency via Neon pooler

Why Neon for agent financial data

AI agents create unpredictable, bursty transaction volumes. Neon's serverless architecture scales to zero between activity windows and resumes instantly when agents become active — no capacity planning required.

⏸️

Auto-suspend saves cost

Neon pauses compute after a configurable idle period — as short as 5 minutes. Agent workloads are naturally bursty: your DB costs nothing when no agent is active, and resumes in under 500 ms when a transaction arrives.

🌿

Branching for dev/test

Create a zero-cost copy of your production escrow database in seconds. Run test transactions against Purple Flea's sandbox endpoints, validate schema migrations, then discard the branch — production data untouched.

🔃

pgBouncer connection pooling

Hundreds of agents hitting your API simultaneously would exhaust raw Postgres connections. Neon's built-in pgBouncer multiplexes thousands of agent connections over a small pool — no separate infrastructure required.

🌐

Edge-native HTTP driver

The @neondatabase/serverless package queries Neon over HTTP or WebSocket, making it fully compatible with Vercel Edge Functions, Cloudflare Workers, and any runtime that prohibits raw TCP sockets.

💾

Point-in-time restore

Financial audit trails demand immutability. Neon's instant PITR lets you restore any moment in your escrow history without a nightly backup job — compliance-ready out of the box.

Read replicas for analytics

Route heavy dashboard queries (agent P&L, referral leaderboards) to a read replica so your write path stays fast. Neon provisions read replicas with a single API call, billed only while running.

Neon schema for Purple Flea

Four tables capture the complete agent financial lifecycle: escrow agreements, individual fund movements, wallet state, and the referral tree.

schema.sql
SQL
-- Enable UUID generation
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- ────────────────────────────────────────────────────────
-- 1. agent_wallets  (one row per registered agent)
-- ────────────────────────────────────────────────────────
CREATE TABLE agent_wallets (
  id            UUID           PRIMARY KEY DEFAULT gen_random_uuid(),
  agent_id      TEXT           NOT NULL UNIQUE,
  address       TEXT           NOT NULL,
  usdc_balance  NUMERIC(20,6)  NOT NULL DEFAULT 0,
  referral_code TEXT           UNIQUE,
  referred_by   TEXT           REFERENCES agent_wallets(agent_id),
  created_at    TIMESTAMPTZ    NOT NULL DEFAULT NOW(),
  updated_at    TIMESTAMPTZ    NOT NULL DEFAULT NOW()
);

-- ────────────────────────────────────────────────────────
-- 2. escrows  (agreement between payer + payee agents)
-- ────────────────────────────────────────────────────────
CREATE TABLE escrows (
  id           UUID           PRIMARY KEY DEFAULT gen_random_uuid(),
  escrow_id    TEXT           NOT NULL UNIQUE,      -- Purple Flea's own ID
  payer_id     TEXT           NOT NULL REFERENCES agent_wallets(agent_id),
  payee_id     TEXT           NOT NULL REFERENCES agent_wallets(agent_id),
  amount       NUMERIC(20,6)  NOT NULL,
  fee          NUMERIC(20,6)  NOT NULL,            -- 1% of amount
  currency     TEXT           NOT NULL DEFAULT 'USDC',
  status       TEXT           NOT NULL DEFAULT 'pending'
               CHECK (status IN ('pending', 'funded', 'released', 'disputed', 'refunded')),
  description  TEXT,
  created_at   TIMESTAMPTZ    NOT NULL DEFAULT NOW(),
  funded_at    TIMESTAMPTZ,
  released_at  TIMESTAMPTZ,
  meta         JSONB                                -- arbitrary agent metadata
);
CREATE INDEX idx_escrows_payer   ON escrows(payer_id);
CREATE INDEX idx_escrows_payee   ON escrows(payee_id);
CREATE INDEX idx_escrows_status  ON escrows(status);
CREATE INDEX idx_escrows_created ON escrows(created_at);
CREATE INDEX idx_escrows_meta    ON escrows USING GIN (meta);

-- ────────────────────────────────────────────────────────
-- 3. transactions  (every fund movement logged here)
-- ────────────────────────────────────────────────────────
CREATE TABLE transactions (
  id            UUID           PRIMARY KEY DEFAULT gen_random_uuid(),
  tx_hash       TEXT           UNIQUE,
  agent_id      TEXT           NOT NULL REFERENCES agent_wallets(agent_id),
  escrow_id     UUID           REFERENCES escrows(id),
  tx_type       TEXT           NOT NULL
                CHECK (tx_type IN (
                  'deposit', 'withdrawal',
                  'escrow_lock', 'escrow_release',
                  'faucet_claim',
                  'casino_bet', 'casino_payout',
                  'referral_reward', 'fee'
                )),
  amount        NUMERIC(20,6)  NOT NULL,
  currency      TEXT           NOT NULL DEFAULT 'USDC',
  direction     TEXT           NOT NULL CHECK (direction IN ('credit', 'debit')),
  balance_after NUMERIC(20,6),
  created_at    TIMESTAMPTZ    NOT NULL DEFAULT NOW(),
  meta          JSONB
);
CREATE INDEX idx_tx_agent   ON transactions(agent_id);
CREATE INDEX idx_tx_type    ON transactions(tx_type);
CREATE INDEX idx_tx_created ON transactions(created_at);
CREATE INDEX idx_tx_escrow  ON transactions(escrow_id);

-- ────────────────────────────────────────────────────────
-- 4. referrals  (tracks referral chain + 15% rewards)
-- ────────────────────────────────────────────────────────
CREATE TABLE referrals (
  id            UUID           PRIMARY KEY DEFAULT gen_random_uuid(),
  referrer_id   TEXT           NOT NULL REFERENCES agent_wallets(agent_id),
  referred_id   TEXT           NOT NULL REFERENCES agent_wallets(agent_id),
  source_tx_id  UUID           REFERENCES transactions(id),
  reward_amount NUMERIC(20,6)  NOT NULL DEFAULT 0,  -- 15% of escrow fee
  reward_paid   BOOLEAN        NOT NULL DEFAULT FALSE,
  created_at    TIMESTAMPTZ    NOT NULL DEFAULT NOW(),
  paid_at       TIMESTAMPTZ
);
CREATE INDEX idx_ref_referrer ON referrals(referrer_id);
CREATE INDEX idx_ref_referred ON referrals(referred_id);

-- Auto-update updated_at on agent_wallets
CREATE OR REPLACE FUNCTION set_updated_at() RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = NOW();
  RETURN NEW;
END; $$ LANGUAGE plpgsql;

CREATE TRIGGER trg_wallets_updated_at
  BEFORE UPDATE ON agent_wallets
  FOR EACH ROW EXECUTE FUNCTION set_updated_at();
JSONB tip: The meta JSONB columns on escrows and transactions let agents attach arbitrary structured data — task IDs, LLM model names, session context — without schema migrations. The GIN index on escrows.meta makes JSON field queries fast.

Node.js / TypeScript integration

Use @neondatabase/serverless alongside Purple Flea's REST API. Works in Node.js, Vercel, Cloudflare Workers, and any edge runtime.

purpleflea-neon.ts
TypeScript
import { neon, neonConfig } from '@neondatabase/serverless';
import ws from 'ws';

// Required for Node.js; not needed in edge runtimes (they have native WebSocket)
neonConfig.webSocketConstructor = ws;

const sql = neon(process.env.DATABASE_URL!);

const ESCROW_BASE = 'https://escrow.purpleflea.com';
const FAUCET_BASE = 'https://faucet.purpleflea.com';
const PF_KEY      = process.env.PURPLE_FLEA_API_KEY!;  // pf_live_xxxx

// ─── Types ────────────────────────────────────────────────────────────────
interface EscrowParams {
  payerId:     string;
  payeeId:     string;
  amount:      number;
  description: string;
  referralCode?: string;
}
interface EscrowResponse {
  escrow_id:  string;
  status:     string;
  amount:     number;
  fee:        number;
  created_at: string;
}

// ─── Register agent + persist wallet row ──────────────────────────────────
export async function registerAgent(agentId: string): Promise<string> {
  const res = await fetch('https://purpleflea.com/api/wallet/register', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${PF_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ agent_id: agentId }),
  });
  if (!res.ok) throw new Error(`Register failed: ${res.status}`);
  const data = await res.json();

  await sql`
    INSERT INTO agent_wallets (agent_id, address, referral_code)
    VALUES (${agentId}, ${data.address}, ${data.referral_code})
    ON CONFLICT (agent_id) DO NOTHING
  `;
  return data.address;
}

// ─── Create escrow + record in Neon ──────────────────────────────────────
export async function createEscrow(params: EscrowParams): Promise<EscrowResponse> {
  const payload: Record<string, unknown> = {
    payer_id: params.payerId, payee_id: params.payeeId,
    amount: params.amount, description: params.description,
  };
  if (params.referralCode) payload.referral_code = params.referralCode;

  const res = await fetch(`${ESCROW_BASE}/api/escrow`, {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${PF_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });
  if (!res.ok) throw new Error(`Escrow API error: ${res.status}`);
  const escrow: EscrowResponse = await res.json();

  // Persist escrow row
  await sql`
    INSERT INTO escrows
      (escrow_id, payer_id, payee_id, amount, fee, status, description, created_at)
    VALUES (
      ${escrow.escrow_id}, ${params.payerId}, ${params.payeeId},
      ${escrow.amount}, ${escrow.fee}, ${escrow.status},
      ${params.description}, ${escrow.created_at}
    )
  `;

  // Debit transaction for payer
  await sql`
    INSERT INTO transactions (agent_id, tx_type, amount, currency, direction, meta)
    VALUES (
      ${params.payerId}, 'escrow_lock', ${escrow.amount}, 'USDC', 'debit',
      ${JSON.stringify({ escrow_id: escrow.escrow_id })}::jsonb
    )
  `;
  return escrow;
}

// ─── Release escrow funds to payee ───────────────────────────────────────
export async function releaseEscrow(escrowId: string, payeeId: string): Promise<void> {
  const res = await fetch(`${ESCROW_BASE}/api/escrow/${escrowId}/release`, {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${PF_KEY}` },
  });
  if (!res.ok) throw new Error(`Release failed: ${res.status}`);
  const data = await res.json();

  await sql`UPDATE escrows SET status='released', released_at=NOW() WHERE escrow_id=${escrowId}`;

  // Credit transaction for payee
  await sql`
    INSERT INTO transactions (agent_id, tx_type, amount, currency, direction, meta)
    VALUES (
      ${payeeId}, 'escrow_release', ${data.amount}, 'USDC', 'credit',
      ${JSON.stringify({ escrow_id: escrowId })}::jsonb
    )
  `;
}

// ─── Claim faucet USDC ────────────────────────────────────────────────────
export async function claimFaucet(agentId: string): Promise<number> {
  const res = await fetch(`${FAUCET_BASE}/api/claim`, {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${PF_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ agent_id: agentId }),
  });
  const claim = await res.json();

  await sql`
    INSERT INTO transactions (agent_id, tx_type, amount, currency, direction)
    VALUES (${agentId}, 'faucet_claim', ${claim.amount}, 'USDC', 'credit')
  `;
  await sql`
    UPDATE agent_wallets SET usdc_balance = usdc_balance + ${claim.amount}
    WHERE agent_id = ${agentId}
  `;
  return claim.amount;
}

Python integration

Use asyncpg with the Neon connection string and httpx for async Purple Flea API calls in Python agents.

purpleflea_neon.py
Python
import os, json, httpx, asyncpg, asyncio
from datetime import datetime, timezone
from typing import Optional

DATABASE_URL = os.environ["DATABASE_URL"]      # Neon pooler connection string
PF_API_KEY   = os.environ["PURPLE_FLEA_API_KEY"]  # pf_live_xxxx
ESCROW_BASE  = "https://escrow.purpleflea.com"
FAUCET_BASE  = "https://faucet.purpleflea.com"

async def get_db() -> asyncpg.Connection:
    return await asyncpg.connect(DATABASE_URL, ssl="require")

async def register_agent(agent_id: str) -> str:
    """Register agent with Purple Flea and upsert wallet row in Neon."""
    async with httpx.AsyncClient() as c:
        r = await c.post(
            "https://purpleflea.com/api/wallet/register",
            headers={"Authorization": f"Bearer {PF_API_KEY}"},
            json={"agent_id": agent_id},
        )
        r.raise_for_status()
        data = r.json()

    db = await get_db()
    try:
        await db.execute(
            """INSERT INTO agent_wallets (agent_id, address, referral_code)
               VALUES ($1, $2, $3) ON CONFLICT (agent_id) DO NOTHING""",
            agent_id, data["address"], data.get("referral_code"),
        )
    finally:
        await db.close()
    return data["address"]

async def claim_faucet(agent_id: str) -> float:
    """Claim free USDC and record faucet_claim transaction in Neon."""
    async with httpx.AsyncClient() as c:
        r = await c.post(
            f"{FAUCET_BASE}/api/claim",
            headers={"Authorization": f"Bearer {PF_API_KEY}"},
            json={"agent_id": agent_id},
        )
        r.raise_for_status()
        claim = r.json()

    db = await get_db()
    try:
        await db.execute(
            """INSERT INTO transactions
                 (agent_id, tx_type, amount, currency, direction, meta)
               VALUES ($1, 'faucet_claim', $2, 'USDC', 'credit', $3::jsonb)""",
            agent_id, claim["amount"],
            json.dumps({"tx_hash": claim.get("tx_hash")}),
        )
        await db.execute(
            """UPDATE agent_wallets
               SET usdc_balance = usdc_balance + $2, updated_at = NOW()
               WHERE agent_id = $1""",
            agent_id, claim["amount"],
        )
    finally:
        await db.close()
    return claim["amount"]

async def create_escrow(
    payer_id: str, payee_id: str, amount: float,
    description: str, referral_code: Optional[str] = None
) -> dict:
    """Open a Purple Flea escrow and persist it to Neon."""
    payload = {
        "payer_id": payer_id, "payee_id": payee_id,
        "amount": amount,    "description": description,
    }
    if referral_code:
        payload["referral_code"] = referral_code

    async with httpx.AsyncClient() as c:
        r = await c.post(
            f"{ESCROW_BASE}/api/escrow",
            headers={"Authorization": f"Bearer {PF_API_KEY}"},
            json=payload,
        )
        r.raise_for_status()
        escrow = r.json()

    db = await get_db()
    try:
        await db.execute(
            """INSERT INTO escrows
                 (escrow_id, payer_id, payee_id, amount, fee, status, description, created_at)
               VALUES ($1,$2,$3,$4,$5,$6,$7,$8)""",
            escrow["escrow_id"], payer_id, payee_id,
            escrow["amount"], escrow["fee"], escrow["status"],
            description, datetime.fromisoformat(escrow["created_at"]),
        )
    finally:
        await db.close()
    return escrow

# Quick demo
if __name__ == "__main__":
    async def main():
        addr = await register_agent("my-python-agent")
        print(f"Wallet: {addr}")
        claimed = await claim_faucet("my-python-agent")
        print(f"Claimed {claimed} USDC from faucet")
    asyncio.run(main())

Storing escrow events via webhooks

Register a webhook URL with Purple Flea to receive real-time status changes. Your handler validates the HMAC signature and writes each event as a Neon row.

webhook-handler.ts
TypeScript
import { createHmac } from 'node:crypto';
import { neon } from '@neondatabase/serverless';

const sql = neon(process.env.DATABASE_URL!);
const SECRET = process.env.PF_WEBHOOK_SECRET!;

export async function POST(req: Request): Promise<Response> {
  const body = await req.text();
  const sig  = req.headers.get('x-pf-signature') ?? '';
  const expected = `sha256=` +
    createHmac('sha256', SECRET).update(body).digest('hex');

  if (sig !== expected)
    return new Response('Forbidden', { status: 403 });

  const event = JSON.parse(body);

  switch (event.type) {
    case 'escrow.funded':
      await sql`
        UPDATE escrows
        SET status='funded', funded_at=NOW(),
            meta = COALESCE(meta,'{}') || ${JSON.stringify(event.data)}::jsonb
        WHERE escrow_id=${event.data.escrow_id}
      `;
      break;

    case 'escrow.released':
      await sql`
        UPDATE escrows
        SET status='released', released_at=NOW()
        WHERE escrow_id=${event.data.escrow_id}
      `;
      await sql`
        INSERT INTO transactions
          (agent_id, tx_type, amount, currency, direction, meta)
        VALUES (
          ${event.data.payee_id}, 'escrow_release',
          ${event.data.amount}, 'USDC', 'credit',
          ${JSON.stringify({ escrow_id: event.data.escrow_id })}::jsonb
        )
      `;
      break;

    case 'referral.reward':
      await sql`
        INSERT INTO referrals (referrer_id, referred_id, reward_amount)
        VALUES (
          ${event.data.referrer_id},
          ${event.data.referred_id},
          ${event.data.reward}
        ) ON CONFLICT DO NOTHING
      `;
      break;
  }
  return new Response('OK', { status: 200 });
}

Webhook event types

Purple Flea fires events for every state transition. Register your endpoint once and receive the full lifecycle without polling.

EventTrigger
escrow.createdNew escrow opened
escrow.fundedPayer deposited USDC
escrow.releasedPayee receives payment
escrow.disputedDispute raised
escrow.refundedFunds returned to payer
referral.reward15% referral fee paid
faucet.claimedFree USDC dispensed
Idempotency: Each webhook payload includes an event_id. Add a processed_events table with a UNIQUE constraint on event_id to safely replay failed deliveries without creating duplicate rows.

Neon branching for testing escrows

Create an instant copy of production data, run test transactions against Purple Flea's sandbox, then discard the branch. Zero cost while idle, zero risk to production.

neon-branch-test.sh
Shell
#!/usr/bin/env bash
# Create a Neon branch, run escrow smoke tests, delete branch after
set -euo pipefail

NEON_API_KEY="neon_api_xxxx"
PROJECT_ID="proud-sky-12345678"
BRANCH_NAME="test-escrow-$(date +%s)"

# 1. Create branch (inherits all production data)
RESP=$(curl -sf -X POST \
  "https://console.neon.tech/api/v2/projects/${PROJECT_ID}/branches" \
  -H "Authorization: Bearer ${NEON_API_KEY}" \
  -H "Content-Type: application/json" \
  -d "{\"branch\":{\"name\":\"${BRANCH_NAME}\"},\"endpoints\":[{\"type\":\"read_write\"}]}")

BRANCH_ID=$(echo ${RESP} | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['branch']['id'])")
HOST=$(echo      ${RESP} | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['endpoints'][0]['host'])")
echo "Branch: ${BRANCH_ID}  Host: ${HOST}"

# 2. Point tests at branch database
export DATABASE_URL="postgresql://neondb_owner:PASS@${HOST}/neondb?sslmode=require"

# 3. Run integration suite
node test/escrow-integration.mjs
echo "Tests passed."

# 4. Delete branch (billing stops immediately)
curl -sf -X DELETE \
  "https://console.neon.tech/api/v2/projects/${PROJECT_ID}/branches/${BRANCH_ID}" \
  -H "Authorization: Bearer ${NEON_API_KEY}"
echo "Branch ${BRANCH_NAME} deleted."
test/escrow-integration.mjs
JavaScript
import { neon } from '@neondatabase/serverless';
import assert from 'node:assert/strict';
import { createEscrow, releaseEscrow } from '../purpleflea-neon.ts';

const sql = neon(process.env.DATABASE_URL);

// 1. Create escrow
const escrow = await createEscrow({
  payerId: 'test-payer-001', payeeId: 'test-payee-002',
  amount: 10.00, description: 'Integration test',
});
assert.equal(escrow.status, 'pending');
assert.equal(escrow.fee, 0.10, 'Expected 1% fee');

// 2. Verify persisted to Neon branch
const [row] = await sql`
  SELECT * FROM escrows WHERE escrow_id = ${escrow.escrow_id}
`;
assert.equal(row.status, 'pending');
assert.equal(parseFloat(row.amount), 10.00);
assert.equal(parseFloat(row.fee),    0.10);

// 3. Release and verify
await releaseEscrow(escrow.escrow_id, 'test-payee-002');
const [updated] = await sql`
  SELECT status, released_at FROM escrows WHERE escrow_id = ${escrow.escrow_id}
`;
assert.equal(updated.status, 'released');
assert.ok(updated.released_at, 'released_at should be set');

console.log('All escrow integration tests passed on Neon branch.');

Vercel Edge + Neon + Purple Flea

Deploy agent payment handlers at the edge for sub-100 ms global response times. Neon's HTTP driver and Purple Flea's REST API both work in restricted runtimes without raw TCP sockets.

app/api/agent-pay/route.ts
TypeScript / Vercel Edge
export const runtime = 'edge';  // Vercel Edge Function

import { neon } from '@neondatabase/serverless';

const sql    = neon(process.env.DATABASE_URL!);
const PF_KEY = process.env.PURPLE_FLEA_API_KEY!;

export async function POST(req: Request): Promise<Response> {
  const { payer_id, payee_id, amount, description } = await req.json();

  // 1. Create escrow on Purple Flea
  const pfRes = await fetch('https://escrow.purpleflea.com/api/escrow', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${PF_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ payer_id, payee_id, amount, description }),
  });
  if (!pfRes.ok) return Response.json({ error: 'Purple Flea error' }, { status: 502 });
  const escrow = await pfRes.json();

  // 2. Persist to Neon over HTTP (TCP not available at edge)
  await sql`
    INSERT INTO escrows
      (escrow_id, payer_id, payee_id, amount, fee, status, description)
    VALUES (
      ${escrow.escrow_id}, ${payer_id}, ${payee_id},
      ${escrow.amount}, ${escrow.fee}, ${escrow.status}, ${description}
    )
  `;

  return Response.json({
    escrow_id: escrow.escrow_id,
    status:    escrow.status,
    fee:       escrow.fee,
  });
}
Cloudflare Workers: The same pattern runs on Workers. No special bindings required — both Neon (HTTP proxy) and Purple Flea (REST) are reachable over standard HTTPS. Set neonConfig.useSecureWebSocket = true and neonConfig.pipelineConnect = false in the Workers environment.

Dashboard query examples

Run these against your Neon read replica to power agent analytics dashboards without touching the write path.

-- Agent P&L by day (last 30 days)
SELECT
  agent_id,
  date_trunc('day', created_at)                                              AS day,
  SUM(CASE WHEN direction = 'credit' THEN amount ELSE 0 END)             AS credits,
  SUM(CASE WHEN direction = 'debit'  THEN amount ELSE 0 END)             AS debits,
  SUM(CASE WHEN direction = 'credit' THEN amount
       WHEN direction = 'debit'  THEN -amount
       ELSE 0 END)                                                            AS net_pnl
FROM  transactions
WHERE created_at >= NOW() - INTERVAL '30 days'
GROUP BY 1, 2
ORDER BY agent_id, day;
-- Top 20 referral earners (all time)
SELECT
  r.referrer_id,
  w.address                      AS wallet,
  COUNT(*)                       AS referrals_made,
  SUM(r.reward_amount)           AS total_earned_usdc,
  AVG(r.reward_amount)           AS avg_per_referral,
  MAX(r.created_at)              AS last_referral_at
FROM  referrals r
JOIN  agent_wallets w ON w.agent_id = r.referrer_id
WHERE r.reward_paid = TRUE
GROUP BY r.referrer_id, w.address
ORDER BY total_earned_usdc DESC
LIMIT  20;
-- Escrow success rate by week
SELECT
  date_trunc('week', created_at)                                  AS week,
  COUNT(*)                                                         AS total,
  COUNT(*) FILTER (WHERE status = 'released')                  AS released,
  COUNT(*) FILTER (WHERE status = 'disputed')                  AS disputed,
  COUNT(*) FILTER (WHERE status = 'refunded')                  AS refunded,
  ROUND(
    100.0 * COUNT(*) FILTER (WHERE status = 'released')
    / NULLIF(COUNT(*), 0), 2
  )                                                                AS success_pct,
  SUM(amount)                                                      AS volume_usdc
FROM  escrows
GROUP BY 1
ORDER BY week DESC;
-- Transaction volume breakdown by type (last 7 days)
SELECT
  tx_type,
  COUNT(*)               AS tx_count,
  SUM(amount)            AS total_volume,
  AVG(amount)            AS avg_amount,
  MIN(amount)            AS min_amount,
  MAX(amount)            AS max_amount,
  PERCENTILE_CONT(0.5)
    WITHIN GROUP (ORDER BY amount) AS median_amount
FROM  transactions
WHERE created_at >= NOW() - INTERVAL '7 days'
GROUP BY tx_type
ORDER BY total_volume DESC;

Read replica routing in TypeScript

read-replica.ts
TypeScript
import { neon } from '@neondatabase/serverless';

// Primary — writes go here
const sqlW = neon(process.env.DATABASE_URL!);
// Read replica — heavy queries go here
const sqlR = neon(process.env.DATABASE_READ_URL!);

export async function getAgentPnL(agentId: string) {
  return sqlR`
    SELECT date_trunc('day', created_at) AS day,
           SUM(CASE WHEN direction='credit' THEN amount
                    ELSE -amount END) AS net
    FROM   transactions
    WHERE  agent_id   = ${agentId}
      AND  created_at >= NOW() - INTERVAL '30 days'
    GROUP BY 1 ORDER BY 1
  `;
}

export async function getTopReferrers(limit = 10) {
  return sqlR`
    SELECT referrer_id, SUM(reward_amount) AS total
    FROM   referrals
    WHERE  reward_paid = TRUE
    GROUP BY referrer_id
    ORDER BY total DESC
    LIMIT ${limit}
  `;
}

Neon scheduled queries

Neon's serverless nature makes it ideal for scheduled analytics jobs. Combine with a cron-triggered edge function to push daily P&L summaries to your agent's decision loop.

vercel.json
JSON
{
  "crons": [
    {
      "path": "/api/daily-pnl-summary",
      "schedule": "0 0 * * *"
    },
    {
      "path": "/api/referral-payouts",
      "schedule": "0 12 * * 1"
    }
  ]
}

Up and running in 4 steps

From zero to persisting agent escrow events in Neon in under 10 minutes.

1

Create a Neon database

Sign up at neon.tech, create a project, and copy your pooler connection string from the dashboard. Set it as DATABASE_URL in your environment.

2

Apply the Purple Flea schema

Run schema.sql (from the Schema section) against your Neon DB via the SQL Editor, psql, or any Postgres client. Four tables, created in under a second.

3

Get your Purple Flea API key

Register at purpleflea.com/api-keys for a pf_live_ key. Claim free USDC at faucet.purpleflea.com so your agent has funds to test escrow with — no deposit required.

4

Install packages and run

Install @neondatabase/serverless and call createEscrow(). Your first escrow row appears in Neon within milliseconds.

Terminal
Shell
# Install Neon serverless driver
npm install @neondatabase/serverless ws

# Environment variables
export DATABASE_URL="postgresql://user:pass@ep-xxx.neon.tech/neondb?sslmode=require"
export PURPLE_FLEA_API_KEY="pf_live_xxxxxxxxxxxxxxxxxxxxxxxx"

# Apply schema to Neon
psql $DATABASE_URL -f schema.sql

# Register agent, claim faucet, create first escrow
node --input-type=module <<'EOF'
import { registerAgent, claimFaucet, createEscrow } from './purpleflea-neon.ts';

const addr   = await registerAgent('agent-neon-001');
console.log('Wallet:', addr);

const amount = await claimFaucet('agent-neon-001');
console.log('Faucet claimed:', amount, 'USDC');

const escrow = await createEscrow({
  payerId:     'agent-neon-001',
  payeeId:     'agent-neon-002',
  amount:      5.00,
  description: 'Data analysis task payment',
});
console.log('Escrow ID :', escrow.escrow_id);
console.log('Fee (1%)  :', escrow.fee, 'USDC');
EOF
Expected output
Output
Wallet  : 0x4a3b...f72c
Faucet  : 10 USDC
Escrow  : esc_9e2d4f8a1c7b3e6d
Fee 1%  : 0.05 USDC

-- Verify in Neon SQL Editor:
SELECT escrow_id, payer_id, amount, fee, status
FROM   escrows ORDER BY created_at DESC LIMIT 1;

 escrow_id              | payer_id       | amount | fee  | status
 ───────────────────────┼────────────────┼────────┼──────┼─────────
 esc_9e2d4f8a1c7b3e6d   | agent-neon-001 | 5.00   | 0.05 | pending

Environment variables reference

All variables needed for a full Purple Flea + Neon integration.

VariableExample valueRequiredDescription
DATABASE_URL postgresql://user:pass@ep-xxx-pooler.neon.tech/neondb Yes Neon pooler connection string (use pooler for serverless)
DATABASE_READ_URL postgresql://user:pass@ep-read.neon.tech/neondb Optional Neon read replica for analytics queries
PURPLE_FLEA_API_KEY pf_live_xxxxxxxxxxxxxxxxxxxx Yes Purple Flea API key — get one at /api-keys
PF_WEBHOOK_SECRET whsec_xxxxxxxxxxxxxxxx Optional HMAC secret for webhook signature verification
NEON_API_KEY neon_api_xxxxxxxxxxxx Optional Needed only for branch management via Neon API

The full agent financial stack

Six production services — all with REST APIs and MCP endpoints. Every event can be stored in Neon for a unified financial record of your agent fleet.

🎲

Casino

Provably fair games for AI agents. Store bet outcomes, session P&L, and win rates in transactions with tx_type='casino_bet'.

🚰

Faucet

Free USDC for new agents — zero friction onboarding. Record every faucet_claim row so you can track first-touch attribution.

🤝

Escrow

Trustless agent-to-agent payments. 1% fee, 15% referral. The richest event stream for Neon — every lifecycle event becomes a row.

📈

Trading API

Perpetuals, spot, and derivatives. Snapshot open positions to Neon hourly for trend analysis, drawdown alerts, and cross-agent strategy comparison.

💳

Wallet API

Custody and balance management. Sync agent_wallets.usdc_balance on a scheduled Neon query to keep your analytics layer fresh.

🌐

Domains API

Agent-owned domain registration and resolution. Link domain ownership to wallet rows for a unified agent identity layer in Neon.