Daily Generation Limits and AI Credits System in prompts.chat: Complete Technical Guide

The prompts.chat AI credits system limits users to a default of 3 generated media items per day by tracking generationCreditsRemaining on the User table, automatically decrementing credits atomically on each successful generation, and restoring quotas via a protected cron job at midnight.

The open-source prompts.chat repository implements a robust rate-limiting mechanism to prevent abuse of AI media generation APIs. This system balances user experience with resource protection through database-level atomic operations, scheduled credit resets, and administrative override capabilities.

Database Schema for Credit Management

The foundation of the AI credits system rests on three columns defined in the User model within prisma/schema.prisma. These fields store the complete state necessary for quota enforcement:

  • dailyGenerationLimit – The maximum number of credits granted per day (defaults to 3).
  • generationCreditsRemaining – The current balance of available generations for today.
  • generationCreditsResetAt – Timestamp tracking when credits were last replenished.
// prisma/schema.prisma (lines 31-34)
model User {
  dailyGenerationLimit       Int      @default(3)
  generationCreditsRemaining Int      @default(3)
  generationCreditsResetAt   DateTime @default(now())
  // ... other fields
}

This schema design allows for per-user customization while maintaining sensible defaults for new registrations.

Checking Credit Status and Consuming Credits

The src/app/api/media-generate/route.ts file handles both credit inquiry and consumption through distinct HTTP methods.

Fetching Current Quota (GET)

When clients query available credits, the endpoint returns the remaining count, daily limit, and a boolean flag indicating whether generation is permitted:

// src/app/api/media-generate/route.ts (lines 22-42)
export async function GET(request: Request) {
  const user = await getCurrentUser();
  return Response.json({
    credits: user.generationCreditsRemaining,
    dailyLimit: user.dailyGenerationLimit,
    canGenerate: user.generationCreditsRemaining > 0 && !user.isBanned
  });
}

Atomic Credit Consumption (POST)

Upon receiving a generation request, the server validates available credits before invoking the media-generation plugin. Crucially, the system uses Prisma's atomic decrement operation to prevent race conditions when multiple requests arrive simultaneously:

// src/app/api/media-generate/route.ts (lines 53-80)
export async function POST(request: Request) {
  const user = await getCurrentUser();
  
  if (user.generationCreditsRemaining <= 0) {
    return Response.json({ error: 'No credits remaining' }, { status: 403 });
  }
  
  await prisma.user.update({
    where: { id: user.id },
    data: { 
      generationCreditsRemaining: { decrement: 1 } 
    }
  });
  
  // Proceed with media generation...
}

This atomic decrement ensures accurate credit tracking even under high concurrency.

Automated Daily Credit Resets

The system restores user quotas automatically through a protected cron endpoint at src/app/api/cron/reset-credits/route.ts.

Cron Job Implementation

A Vercel or GitHub Actions scheduled task invokes POST /api/cron/reset-credits with a secret authorization header. The endpoint executes a raw SQL update to efficiently reset all users simultaneously:

// src/app/api/cron/reset-credits/route.ts (lines 38-45)
export async function POST(request: Request) {
  const authHeader = request.headers.get('authorization');
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 });
  }
  
  await prisma.$executeRaw`
    UPDATE "User" 
    SET "generationCreditsRemaining" = "dailyGenerationLimit",
        "generationCreditsResetAt" = NOW()
  `;
  
  return Response.json({ success: true, resetCount: ... });
}

This approach scales efficiently because it performs a single database operation across all records rather than iterating through individual users.

Administrative Credit Controls

Administrators can override individual user limits through a dedicated API endpoint and React-based admin interface.

API Endpoint for Limit Adjustments

The src/app/api/admin/users/[id]/route.ts file exposes a PATCH handler that accepts new daily limits and optionally resets remaining credits immediately:

// src/app/api/admin/users/[id]/route.ts (lines 16-60)
export async function PATCH(
  request: Request,
  { params }: { params: { id: string } }
) {
  const { dailyGenerationLimit, resetCredits } = await request.json();
  
  const updateData: any = { dailyGenerationLimit };
  
  if (resetCredits) {
    updateData.generationCreditsRemaining = dailyGenerationLimit;
  }
  
  const updatedUser = await prisma.user.update({
    where: { id: params.id },
    data: updateData
  });
  
  return Response.json(updatedUser);
}

Admin User Interface

The src/components/admin/users-table.tsx component (lines 55-64) provides an "Edit Credits" dialog that interfaces with this PATCH endpoint, allowing non-technical administrators to adjust quotas through the web UI rather than manual database queries.

Client-Side Integration Example

Applications consuming the prompts.chat API typically implement this flow:

// 1. Check current quota
const { credits, dailyLimit, canGenerate } = await fetch('/api/media-generate')
  .then(r => r.json());

// 2. Conditionally enable generation button
if (canGenerate) {
  const response = await fetch('/api/media-generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      prompt: 'A cyberpunk city at dusk',
      model: 'stable-diffusion',
      type: 'image',
      provider: 'stability'
    })
  });
  // Server automatically decrements credits on success
}

Manual Operations

Triggering Credit Reset Manually

For testing or emergency resets, administrators can invoke the cron endpoint directly:

curl -X POST https://your-domain.com/api/cron/reset-credits \
  -H "Authorization: Bearer YOUR_CRON_SECRET"

Updating User Limits via API

To grant specific users higher quotas without UI interaction:

curl -X PATCH https://your-domain.com/api/admin/users/USER_ID \
  -H "Content-Type: application/json" \
  -d '{"dailyGenerationLimit": 10, "resetCredits": true}'

Summary

  • Three database fields (dailyGenerationLimit, generationCreditsRemaining, generationCreditsResetAt) in prisma/schema.prisma store the complete credit state for each user.
  • Atomic decrement operations in src/app/api/media-generate/route.ts prevent race conditions when consuming credits during high-traffic generation requests.
  • Default allowance of 3 credits per day applies automatically to new users unless overridden by administrators.
  • Protected cron endpoint at src/app/api/cron/reset-credits/route.ts restores all user quotas daily using raw SQL for performance.
  • Admin controls allow dynamic adjustment of individual limits through both REST API (/api/admin/users/[id]) and React UI components without requiring database access.

Frequently Asked Questions

How does prompts.chat prevent users from exceeding their daily generation limits?

The system enforces limits through server-side validation in src/app/api/media-generate/route.ts. Before processing any generation request, the handler checks generationCreditsRemaining and rejects requests with a 403 status if the value is zero or negative. Credits are then decremented atomically using Prisma's decrement operator to ensure accuracy even with concurrent requests.

What happens when the daily generation limit is increased for an existing user?

When administrators call the PATCH endpoint at src/app/api/admin/users/[id]/route.ts with a higher dailyGenerationLimit, the change applies immediately to future cycles. If the resetCredits flag is included in the request, the system also updates generationCreditsRemaining to match the new limit instantly, granting additional generations for the current day.

How can I manually reset credits for all users before the scheduled cron job?

Send a POST request to /api/cron/reset-credits with the Authorization: Bearer YOUR_CRON_SECRET header. This triggers the same logic as the automated midnight reset, executing a raw SQL update that copies dailyGenerationLimit into generationCreditsRemaining for every user in the database and updates the generationCreditsResetAt timestamp.

Why does the system use Prisma's atomic decrement instead of standard update operations?

Atomic decrement prevents race conditions where two simultaneous generation requests might both read the same credit balance before either writes back, resulting in only one credit being deducted for two generations. By using Prisma's { decrement: 1 } operation, the database handles the subtraction at the SQL level, ensuring accurate counting even under heavy concurrent load.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →