How to Integrate Anthropic for payments with pgvector for production AI

By Cyprian AaronsUpdated 2026-04-21
anthropic-for-paymentspgvectorproduction-ai

Combining Anthropic with pgvector gives you a clean pattern for production AI agents that need both reasoning and retrieval. In practice, this means your agent can answer from company knowledge stored in vectors, then route payment-related actions through Anthropic-backed workflows with traceable context.

For banks and insurance systems, that matters because you want the model to see only the right retrieved facts before it makes a payment decision. pgvector handles semantic search over policies, invoices, claims, or transaction notes; Anthropic handles the language layer that decides what to do next.

Prerequisites

  • Python 3.10+
  • PostgreSQL 14+ with the pgvector extension installed
  • An Anthropic API key
  • A PostgreSQL user with permission to create tables and extensions
  • psycopg or psycopg2-binary
  • anthropic Python SDK
  • A working payments backend or sandbox endpoint if you are triggering payment actions from the agent
  • Basic environment variables set:
    • ANTHROPIC_API_KEY
    • DATABASE_URL

Integration Steps

  1. Install dependencies and enable pgvector

    Start by installing the Python packages and enabling the vector extension in Postgres.

    pip install anthropic psycopg[binary] pgvector python-dotenv
    
    import os
    import psycopg
    from dotenv import load_dotenv
    
    load_dotenv()
    
    conn = psycopg.connect(os.environ["DATABASE_URL"])
    conn.execute("CREATE EXTENSION IF NOT EXISTS vector;")
    conn.commit()
    conn.close()
    
  2. Create a vector table for payment-related context

    Store invoice notes, customer messages, policy clauses, or payment instructions as embeddings. Use a fixed embedding dimension that matches your embedding model.

    import os
    import psycopg
    
    conn = psycopg.connect(os.environ["DATABASE_URL"])
    with conn.cursor() as cur:
        cur.execute("""
            CREATE TABLE IF NOT EXISTS payment_docs (
                id BIGSERIAL PRIMARY KEY,
                source ტექst TEXT NOT NULL,
                content TEXT NOT NULL,
                embedding vector(1536)
            );
        """)
        cur.execute("""
            CREATE INDEX IF NOT EXISTS payment_docs_embedding_idx
            ON payment_docs USING ivfflat (embedding vector_cosine_ops)
            WITH (lists = 100);
        """)
        conn.commit()
    conn.close()
    
  3. Generate embeddings with Anthropic-compatible retrieval flow

    Anthropic’s core API is for text generation, so in production you usually pair it with an embedding model service for vectors. If your architecture keeps embeddings outside Anthropic, store them in pgvector and use Anthropic for reasoning over retrieved chunks.

    The pattern below uses an embedding function placeholder and then stores vectors in Postgres.

    import os
    import psycopg
    from anthropic import Anthropic
    
    client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
    
    def embed_text(text: str) -> list[float]:
        # Replace with your embedding provider.
        # Keep the return shape aligned with vector(1536).
        return [0.0] * 1536
    
    docs = [
        ("invoice_1042", "Customer requested a refund after duplicate charge."),
        ("policy_22", "Refunds above $500 require manager approval."),
        ("payment_runbook", "Use ACH for domestic vendor payouts under $10k.")
    ]
    
    conn = psycopg.connect(os.environ["DATABASE_URL"])
    with conn.cursor() as cur:
        for source, content in docs:
            emb = embed_text(content)
            cur.execute(
                "INSERT INTO payment_docs (source, content, embedding) VALUES (%s, %s, %s)",
                (source, content, emb)
            )
        conn.commit()
    conn.close()
    
  4. Retrieve relevant context from pgvector before calling Anthropic

    This is the production pattern: search Postgres first, then send only the top matches to Anthropic. That keeps prompts smaller and decisions grounded in your internal data.

     import os
     import psycopg
     from anthropic import Anthropic
    
     client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
    
     def embed_text(text: str) -> list[float]:
         return [0.0] * 1536
    
     def retrieve_context(query: str, k: int = 3) -> list[str]:
         query_vec = embed_text(query)
         conn = psycopg.connect(os.environ["DATABASE_URL"])
         with conn.cursor() as cur:
             cur.execute(
                 """
                 SELECT source, content
                 FROM payment_docs
                 ORDER BY embedding <=> %s::vector
                 LIMIT %s;
                 """,
                 (query_vec, k),
             )
             rows = cur.fetchall()
         conn.close()
         return [f"{source}: {content}" for source, content in rows]
    
     query = "Can we approve a $700 refund for duplicate billing?"
     context = retrieve_context(query)
    
     message = client.messages.create(
         model="claude-3-5-sonnet-20241022",
         max_tokens=300,
         messages=[
             {
                 "role": "user",
                 "content": f"""
    

You are a payments assistant. Use this internal context:

{chr(10).join(context)}

Question: {query} Return a decision and short rationale. """.strip(), } ], )

print(message.content[0].text)
```

5. Trigger a payment action from the model output

In production, do not let Claude execute payments directly. Parse its structured recommendation, validate it in code, then call your payments service.

import json
import os
import requests

def execute_payment_action(decision_text: str):
    # Example of strict downstream control.
    if "approve" not in decision_text.lower():
        return {"status": "skipped"}

    payload = {
        "amount": 700,
        "currency": "USD",
        "reason": "duplicate billing refund",
        "reference": "refund_1042"
    }

    resp = requests.post(
        os.environ["PAYMENTS_API_URL"],
        headers={"Authorization": f"Bearer {os.environ['PAYMENTS_API_KEY']}"},
        json=payload,
        timeout=10,
    )
    resp.raise_for_status()
    return resp.json()

## Testing the Integration

Run a single end-to-end check: retrieve context from pgvector, ask Anthropic for a decision, then assert the response contains an expected action keyword.

```python
query = "Approve refund for duplicate charge under $500?"
context = retrieve_context(query)

message = client.messages.create(
 model="claude-3-5-sonnet-20241022",
 max_tokens=200,
 messages=[{
     "role": "user",
     "content": f"Context:\n{chr(10).join(context)}\n\nQuestion: {query}\nRespond with APPROVE or REJECT."
 }],
)

result = message.content[0].text.strip().upper()
print(result)

assert result in {"APPROVE", "REJECT"}

Expected output:

APPROVE

If you get empty context back from pgvector, check:

  • Your embeddings dimension matches the table definition.
  • The vector extension is enabled.
  • Your similarity operator uses the same metric you indexed on.
  • You inserted real embeddings instead of placeholder zeros.

Real-World Use Cases

  • Claims payout assistant
    Retrieve claim policy clauses from pgvector, then use Anthropic to decide whether a payout request meets approval rules before calling your payments API.

  • Vendor payment copilot
    Search invoice history and vendor terms in pgvector, then have Anthropic explain whether to pay now, hold for review, or escalate to finance ops.

  • Customer refund triage
    Pull dispute history and refund policy snippets from pgvector, then let Anthropic produce a structured recommendation that your backend turns into an approved refund workflow.


Keep learning

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

Related Guides