How to Integrate Anthropic for payments with pgvector for AI agents
When you build AI agents for payments, the hard part is not the model call. It’s grounding the agent in transaction history, policy data, and merchant context so it can make a safe decision before hitting a payment flow.
That’s where Anthropic plus pgvector fits. Use Anthropic to reason over the payment task, and pgvector to retrieve similar past cases, customer notes, dispute patterns, or policy snippets from your vector store.
Prerequisites
- •Python 3.10+
- •A running PostgreSQL instance with the
pgvectorextension installed - •An Anthropic API key
- •Access to an Anthropic model that supports tool use
- •A PostgreSQL database user with permission to create tables and extensions
- •Python packages:
- •
anthropic - •
psycopg[binary] - •
pgvector - •
openaior another embedding provider if you are generating embeddings outside Anthropic
- •
Install the packages:
pip install anthropic psycopg[binary] pgvector
Enable pgvector in your database:
CREATE EXTENSION IF NOT EXISTS vector;
Integration Steps
1) Create the vector table for payment context
Store payment-related documents as embeddings. In practice, these are refund policies, fraud notes, chargeback examples, KYC exceptions, or merchant-specific handling rules.
import psycopg
from pgvector.psycopg import register_vector
conn = psycopg.connect(
"postgresql://postgres:postgres@localhost:5432/payments"
)
register_vector(conn)
with conn.cursor() as cur:
cur.execute("""
CREATE TABLE IF NOT EXISTS payment_context (
id SERIAL PRIMARY KEY,
source ტექst TEXT NOT NULL,
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
embedding VECTOR(1536) NOT NULL
)
""")
conn.commit()
If your embedding dimension differs, match it to your embedding model. Don’t guess here; a dimension mismatch will fail at insert time.
2) Generate embeddings and insert payment knowledge into pgvector
For production systems, generate embeddings from a dedicated embedding model and store them alongside metadata. The agent will later use similarity search to pull relevant context before deciding how to handle a payment request.
import os
import psycopg
from pgvector.psycopg import register_vector
def embed_text(text: str) -> list[float]:
# Replace with your embedding provider.
# Example shape only.
return [0.01] * 1536
conn = psycopg.connect("postgresql://postgres:postgres@localhost:5432/payments")
register_vector(conn)
rows = [
{
"text": "Refunds under $50 can be auto-approved if the order is delivered late.",
"metadata": {"type": "refund_policy", "region": "US"}
},
{
"text": "Flag any card-not-present payment over $1,000 for manual review.",
"metadata": {"type": "fraud_rule", "severity": "high"}
}
]
with conn.cursor() as cur:
for row in rows:
cur.execute(
"""
INSERT INTO payment_context (source_text, metadata, embedding)
VALUES (%s, %s::jsonb, %s)
""",
(row["text"], row["metadata"], embed_text(row["text"]))
)
conn.commit()
The important part is that every record has text plus structured metadata. That gives you both semantic search and deterministic filtering later.
3) Query pgvector for the most relevant payment context
At runtime, turn the user’s request into an embedding and fetch the closest matches from pgvector. This is what grounds the agent before it calls any payment logic.
import psycopg
from pgvector.psycopg import register_vector
def embed_text(text: str) -> list[float]:
return [0.01] * 1536
query = "Customer wants a refund because delivery arrived two weeks late."
conn = psycopg.connect("postgresql://postgres:postgres@localhost:5432/payments")
register_vector(conn)
with conn.cursor() as cur:
cur.execute(
"""
SELECT source_text, metadata
FROM payment_context
ORDER BY embedding <-> %s
LIMIT 3
""",
(embed_text(query),)
)
matches = cur.fetchall()
for text, metadata in matches:
print(text, metadata)
Use <-> for cosine/L2-style nearest neighbor behavior depending on your index setup and operator class. For larger datasets, add an IVFFlat or HNSW index once you’re past prototype stage.
4) Pass retrieved context into Anthropic for decision-making
Now feed the retrieved snippets into Anthropic and ask it to produce a structured decision. This is where the model turns retrieval into an action plan for the agent.
import os
from anthropic import Anthropic
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
context_block = "\n".join(
f"- {text} | metadata={metadata}"
for text, metadata in matches
)
message = client.messages.create(
model="claude-3-5-sonnet-latest",
max_tokens=400,
messages=[
{
"role": "user",
"content": f"""
You are a payments assistant.
Relevant policy/context:
{context_block}
User request:
{query}
Return:
1. decision: approve / deny / manual_review
2. rationale: short explanation
3. next_action: exact operational step
"""
}
]
)
print(message.content[0].text)
This pattern works because Anthropic handles reasoning while pgvector handles memory. Keep them separate; don’t bury retrieval inside prompt text generation without a database-backed source of truth.
5) Wire both into an agent loop with tool-style control flow
In production, your agent should first retrieve context from pgvector, then call Anthropic with that context, then execute a downstream payments action based on the result.
import json
from anthropic import Anthropic
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
def get_relevant_context(user_query: str):
# reuse your pgvector query here and return top matches
return [
{"text": "Refunds under $50 can be auto-approved if delivered late.", "metadata": {"type": "refund_policy"}}
]
def decide_payment_action(user_query: str):
ctx = get_relevant_context(user_query)
ctx_text = "\n".join([f"{x['text']} | {x['metadata']}" for x in ctx])
resp = client.messages.create(
model="claude-3-5-sonnet-latest",
max_tokens=300,
messages=[{
"role": "user",
"content": f"""
Use this context:
{ctx_text}
Decide whether to approve this request:
{user_query}
Respond as JSON with keys decision and reason.
"""
}]
)
return resp.content[0].text
print(decide_payment_action("Approve a $42 refund for late delivery"))
If you want stricter control, validate the JSON before executing anything downstream. Payment systems should never trust free-form model output directly.
Testing the Integration
Run one end-to-end test that inserts known policy text, retrieves it with pgvector, and asks Anthropic to classify the request.
test_query = "Customer requests a refund for late delivery on a $42 order."
result = decide_payment_action(test_query)
print(result)
Expected output:
{"decision":"approve","reason":"Matches auto-approval policy for late-delivered refunds under $50."}
If you get unrelated retrieval results, fix your embeddings or indexing first. If you get good retrieval but bad decisions, tighten the prompt and require JSON output.
Real-World Use Cases
- •
Refund triage
Retrieve policy snippets and prior cases from pgvector, then let Anthropic decide whether to auto-approve or escalate. - •
Fraud review assistants
Ground suspicious transaction analysis in historical fraud patterns stored in PostgreSQL before generating investigator notes. - •
Payment support copilots
Let support agents ask natural language questions like “why was this card declined?” while the system pulls relevant logs and policy text from vector search.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit