Skip to main content

What You’ll Build

This tutorial walks you through building a FastAPI backend application using the dual-client architecture:
  • Profy (API Key) — Your app’s own API key for calling experts and AI models
  • ProfyApp (OAuth) — Users’ OAuth tokens for reporting billing events to the Profy platform

Prerequisites

Profy Developer Account

A registered Profy account with an App created in the Developer Console — you’ll need the Client ID, Client Secret, and API Key

Development Environment

Python 3.10+, pip, basic FastAPI and async/await experience

Step 1: Project Setup

Create a .env file for your credentials:
.env
Never commit .env to version control. Make sure .gitignore includes this file.

Step 2: Initialize Dual Clients

config.py
Each client serves a distinct purpose: client (Profy) holds your API Key for AI calls; app_client (ProfyApp) holds OAuth credentials for user authorization and billing.

Step 3: Token Storage

Manual token storage implementation. Use a database in production — here we use a dict to demonstrate the core pattern:
token_store.py
Production deployments must use persistent storage (database / Redis). The dict loses all tokens on process restart. See Token Management Best Practices.

Step 4: OAuth Login Flow

main.py

Step 5: Protected Routes

Use FastAPI dependency injection to automatically load and validate tokens:
dependencies.py

Step 6: Report Billing Events

main.py (continued)
The on_refresh callback fires when the token is auto-refreshed. Because Profy’s refresh tokens are single-use (rotation), you must persist the new token in the callback.

Step 7: Call AI

Use the Profy (API Key) client to call experts or AI models — this is independent of the user’s OAuth token:
main.py (continued)

Step 8: Error Handling Middleware

main.py (continued)

Contract limits worth coding against

The billing endpoint enforces these server-side. Validate before you call, so a typo doesn’t surface as a 400 in production:
The SDK will generate an idempotency_key for you if you omit it — but a fresh UUID per attempt defeats the purpose. Derive the key from the unit of work (e.g. f"summarize:{document_id}"), so a retry after a timeout collapses into the same charge instead of double-billing your user.

Failures and fixes

Complete Project Structure

requirements.txt:
requirements.txt
Start the development server:

Deployment Tips

Multi-Worker Deployment

In production, use gunicorn main:app -k uvicorn.workers.UvicornWorker -w 4. With multiple workers, the dict token store isn’t shared — you must use a database or Redis.

Environment Variables

In production, inject credentials via Kubernetes Secrets or cloud platform environment variables instead of .env files. Set secure=True on cookies.

Database Migrations

Use SQLAlchemy + Alembic to manage the token table. Don’t use create_all in production.

Reverse Proxy

Run behind Nginx / Caddy for HTTPS termination. Ensure X-Forwarded-Proto is correctly forwarded.

Next Steps

Next.js Full-Stack Integration

TypeScript version of the dual-client full-stack app

Per-Use Billing

ProfyApp reportEvent per-call billing

Token Management Best Practices

Concurrent refresh, secure storage, degradation strategies

Full SDK Guide

Complete bilingual API reference