We just released our native n8n integration!ยป Try now
OnlyFans API
Examples

Next.js & Prisma

Learn how to integrate @onlyfansapi/auth into a Next.js application with Prisma for persistent account storage.

Overview

This guide walks you through building a complete account management dashboard that:

  • Authenticates OnlyFans accounts using @onlyfansapi/auth
  • Stores account data in a PostgreSQL database via Prisma
  • Provides a UI to view and manage connected accounts

Example Repository

The complete source code is available at auth-example-nextjs-prisma.

Prerequisites

Before starting, ensure you have:

Step 1: Create a Next.js Project

Create a new Next.js project with TypeScript and Tailwind CSS:

npx create-next-app@latest my-app --typescript --tailwind --app
cd my-app

Step 2: Install Dependencies

Install the required packages:

npm install @onlyfansapi/auth prisma @prisma/client @prisma/adapter-pg pg

Step 3: Set Up Prisma

Initialize Prisma with PostgreSQL:

npx prisma init

Update your prisma/schema.prisma to define the Account model:

generator client {
  provider = "prisma-client"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Account {
  id          String   @id @default(cuid())
  accountId   String   @unique  // OnlyFans account ID
  username    String             // OnlyFans username
  displayName String             // User-defined label
  name        String?            // OnlyFans profile name
  avatar      String?            // Avatar URL
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}

Create the Prisma client singleton in lib/prisma.ts:

import { Pool } from "pg";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };

function createPrismaClient() {
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
  const adapter = new PrismaPg(pool);
  return new PrismaClient({ adapter });
}

export const prisma = globalForPrisma.prisma ?? createPrismaClient();

if (process.env.NODE_ENV !== "production") {
  globalForPrisma.prisma = prisma;
}

Step 4: Configure Environment Variables

Create a .env file with your credentials:

# PostgreSQL connection string
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"

# OnlyFans API Key (keep this secret, server-side only)
OFAPI_API_KEY="ofapi_..."

Security Note

The OFAPI_API_KEY should never be exposed to the client. We'll create a server-side endpoint to generate client session tokens.

Step 5: Create the Client Session API Route

Create app/api/client-session/route.ts to securely generate client session tokens:

import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  const body = await request.json();
  const { displayName } = body;

  if (!displayName) {
    return NextResponse.json(
      { error: "displayName is required" },
      { status: 400 }
    );
  }

  const apiKey = process.env.OFAPI_API_KEY;
  if (!apiKey) {
    return NextResponse.json(
      { error: "API key not configured" },
      { status: 500 }
    );
  }

  // Create client session via OnlyFans API
  const response = await fetch(
    "https://app.onlyfansapi.com/api/client-sessions",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`,
      },
      body: JSON.stringify({ display_name: displayName }),
    }
  );

  if (!response.ok) {
    return NextResponse.json(
      { error: "Failed to create client session" },
      { status: response.status }
    );
  }

  const data = await response.json();
  return NextResponse.json({ token: data.data.token });
}

This endpoint calls the Create Client Session API to generate a temporary token for authentication.

Step 6: Create the Accounts API Routes

Create app/api/accounts/route.ts for listing and creating accounts:

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";

export async function GET() {
  const accounts = await prisma.account.findMany({
    orderBy: { createdAt: "desc" },
  });
  return NextResponse.json(accounts);
}

export async function POST(request: NextRequest) {
  const { accountId, username, displayName, name, avatar } = await request.json();

  if (!accountId || !username || !displayName) {
    return NextResponse.json(
      { error: "accountId, username, and displayName are required" },
      { status: 400 }
    );
  }

  const account = await prisma.account.create({
    data: { accountId, username, displayName, name, avatar },
  });

  return NextResponse.json(account, { status: 201 });
}

Create app/api/accounts/[id]/route.ts for deleting accounts:

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";

export async function DELETE(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params;
  await prisma.account.delete({ where: { id } });
  return NextResponse.json({ success: true });
}

Step 7: Build the Dashboard UI

Create a dashboard page in app/page.tsx that uses the auth package:

"use client";

import { useState } from "react";
import { startOnlyFansAuthentication } from "@onlyfansapi/auth";

export default function Dashboard() {
  const [displayName, setDisplayName] = useState("");
  const [isLoading, setIsLoading] = useState(false);

  const handleAddAccount = async () => {
    if (!displayName.trim()) return;

    setIsLoading(true);

    try {
      // Step 1: Get client session token from our backend
      const sessionRes = await fetch("/api/client-session", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ displayName: displayName.trim() }),
      });

      if (!sessionRes.ok) throw new Error("Failed to create session");

      const { token } = await sessionRes.json();

      // Step 2: Start authentication with the token
      startOnlyFansAuthentication(token, {
        onSuccess: async (data) => {
          // Step 3: Save account to database
          await fetch("/api/accounts", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
              accountId: data.accountId,
              username: data.username,
              displayName: displayName.trim(),
              name: data.onlyfansData?.name,
              avatar: data.onlyfansData?.avatar_url,
            }),
          });

          // Refresh account list or show success message
          window.location.reload();
        },
        onError: (error) => {
          console.error("Authentication failed:", error.message);
          setIsLoading(false);
        },
      });
    } catch (error) {
      console.error("Error:", error);
      setIsLoading(false);
    }
  };

  return (
    <div>
      <h1>Account Dashboard</h1>

      <input
        type="text"
        value={displayName}
        onChange={(e) => setDisplayName(e.target.value)}
        placeholder="Enter display name"
      />

      <button onClick={handleAddAccount} disabled={isLoading}>
        {isLoading ? "Connecting..." : "Add Account"}
      </button>
    </div>
  );
}

Step 8: Initialize the Database

Generate the Prisma client and push the schema to your database:

npx prisma generate
npx prisma db push

Step 9: Run the Application

Start the development server:

npm run dev

Open http://localhost:3000 to see your dashboard.

Authentication Flow Summary

  1. User initiates auth: Clicks "Add Account" and enters a display name
  2. Backend creates session: Server calls OnlyFans API to create a client session token
  3. Auth popup opens: startOnlyFansAuthentication() opens a secure popup
  4. User authenticates: User logs into their OnlyFans account
  5. Callback fires: onSuccess receives account data
  6. Account saved: Backend stores account in database via Prisma

Best Practices

Keep API Keys Server-Side

Never expose your OFAPI_API_KEY to the client. Always create client session tokens via a server-side API route.

// โœ… Good: Server-side token generation
const response = await fetch("/api/client-session", { ... });

// โŒ Bad: Client-side API key usage
startOnlyFansAuthentication("ofapi_...", { ... });

Handle Duplicate Accounts

Check for existing accounts before creating:

const existing = await prisma.account.findUnique({
  where: { accountId: data.accountId },
});

if (existing) {
  // Update existing account or show error
}

Store Display Names

The displayName field helps users identify accounts in your dashboard:

body: JSON.stringify({
  accountId: data.accountId,
  username: data.username,
  displayName: "Agency / Model: Stella", // User-defined label
})

TypeScript Support

The auth package includes full TypeScript definitions:

import {
  startOnlyFansAuthentication,
  AuthSuccessData,
  AuthFailureError
} from "@onlyfansapi/auth";

startOnlyFansAuthentication(token, {
  onSuccess: (data: AuthSuccessData) => {
    console.log(data.accountId);  // string
    console.log(data.username);   // string
    console.log(data.onlyfansData.name); // string
  },
  onError: (error: AuthFailureError) => {
    console.log(error.message);   // string
  },
});

Next Steps

On this page