How to Integrate LlamaIndex for payments with Supabase for RAG

By Cyprian AaronsUpdated 2026-04-22
llamaindex-for-paymentssupabaserag

Combining LlamaIndex for payments with Supabase gives you a clean pattern for building paid RAG systems: ingest documents, store embeddings and metadata in Supabase, then gate retrieval or response generation behind payment state. That matters when your agent is serving premium research, metered document access, or invoice-backed workflows where only paying users should retrieve certain context.

Prerequisites

  • Python 3.10+
  • A Supabase project with:
    • SUPABASE_URL
    • SUPABASE_SERVICE_ROLE_KEY or anon key for limited access
  • A Postgres table in Supabase for documents and payment state
  • LlamaIndex installed with the vector store and OpenAI integrations:
    • llama-index
    • llama-index-vector-stores-supabase
    • llama-index-embeddings-openai
    • llama-index-llms-openai
  • A payments provider connected to your app
    • Stripe is the common choice
  • Environment variables set for:
    • OPENAI_API_KEY
    • SUPABASE_URL
    • SUPABASE_SERVICE_ROLE_KEY

Integration Steps

  1. Set up Supabase as your persistence layer.

Use Supabase for two things:

  • vector storage for RAG
  • payment/subscription metadata for access control
import os
from supabase import create_client, Client

supabase_url = os.environ["SUPABASE_URL"]
supabase_key = os.environ["SUPABASE_SERVICE_ROLE_KEY"]

supabase: Client = create_client(supabase_url, supabase_key)

# Example tables you might already have:
# documents(id, content, metadata jsonb, user_id text)
# subscriptions(user_id text primary key, status text, plan text)

print("Supabase client ready")
  1. Configure LlamaIndex to use SupabaseVectorStore.

This is the core RAG integration. LlamaIndex writes embeddings into Supabase and reads them back during retrieval.

import os
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.core.schema import TextNode
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.vector_stores.supabase import SupabaseVectorStore

supabase_vector_store = SupabaseVectorStore(
    postgres_connection_string=os.environ["SUPABASE_POSTGRES_URL"],
    collection_name="rag_documents",
    dimensions=1536,
)

storage_context = StorageContext.from_defaults(vector_store=supabase_vector_store)

embed_model = OpenAIEmbedding(model="text-embedding-3-small")

nodes = [
    TextNode(
        text="Invoice terms: Net 30 applies unless otherwise negotiated.",
        metadata={"doc_type": "billing", "tenant_id": "acme"}
    ),
    TextNode(
        text="Premium support includes priority escalation and SLA reporting.",
        metadata={"doc_type": "support", "tenant_id": "acme"}
    ),
]

index = VectorStoreIndex(nodes=nodes, storage_context=storage_context, embed_model=embed_model)
print("Indexed documents into Supabase")
  1. Store payment state in Supabase and gate retrieval with it.

The pattern here is simple: query subscription status before allowing retrieval. If the user is not paid up, return a billing prompt instead of calling the retriever.

from typing import Optional

def get_subscription_status(user_id: str) -> Optional[str]:
    result = (
        supabase.table("subscriptions")
        .select("status")
        .eq("user_id", user_id)
        .single()
        .execute()
    )
    return result.data["status"] if result.data else None

def can_access_rag(user_id: str) -> bool:
    status = get_subscription_status(user_id)
    return status in {"active", "trialing"}

user_id = "user_123"

if can_access_rag(user_id):
    print("Access granted")
else:
    print("Access denied: subscription inactive")
  1. Build the query path with LlamaIndex retrieval.

Once the user passes the payment check, query the index through a retriever or query engine. Keep the gating outside the model call so access control stays deterministic.

from llama_index.llms.openai import OpenAI

llm = OpenAI(model="gpt-4o-mini")
query_engine = index.as_query_engine(llm=llm, similarity_top_k=3)

def answer_question(user_id: str, question: str) -> str:
    if not can_access_rag(user_id):
        return "Your subscription is inactive. Please renew to access this knowledge base."

    response = query_engine.query(question)
    return str(response)

print(answer_question("user_123", "What are the billing terms?"))
  1. Write back usage events for metering.

If you want usage-based billing, log every successful retrieval or answer generation into Supabase. That gives you auditability and a clean source of truth for invoices.

from datetime import datetime

def log_usage(user_id: str, question: str, source: str = "rag_query"):
    supabase.table("usage_events").insert({
        "user_id": user_id,
        "event_type": source,
        "payload": {"question": question},
        "created_at": datetime.utcnow().isoformat()
    }).execute()

def answer_and_log(user_id: str, question: str) -> str:
    if not can_access_rag(user_id):
        return "Subscription required."

    answer = str(query_engine.query(question))
    log_usage(user_id, question)
    return answer

Testing the Integration

Run a basic smoke test against both systems:

test_user = "user_123"
test_question = "Summarize our premium support policy."

status = get_subscription_status(test_user)
print("subscription_status:", status)

if can_access_rag(test_user):
    result = query_engine.query(test_question)
    print("answer:", result)
else:
    print("blocked: inactive subscription")

Expected output:

subscription_status: active
answer: Premium support includes priority escalation and SLA reporting.

If the subscription is inactive:

subscription_status: inactive
blocked: inactive subscription

Real-World Use Cases

  • Paid internal knowledge assistants
    Let employees or customers query policy docs only after their account status is verified in Supabase.

  • Metered document intelligence
    Track each retrieval or response as a usage event and bill per request, per token bucket, or per document class.

  • Tiered support agents
    Basic users get general answers; premium users unlock deeper manuals, incident playbooks, and contract-specific context stored in RAG.


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