Explainers

CaptchaAI for Teams: Multi-User API Key Management

When multiple team members or services use CaptchaAI, you need key management, usage tracking, and spending controls. Here's how to set it up.


Team Usage Patterns

Pattern When to Use
Single shared key Small team, simple tracking
Key per user Per-user spending limits and audit
Key per project Cost allocation by project
Key per environment Dev/staging/prod isolation

Team Key Manager

import os
import json
import time
import threading
from collections import defaultdict


class TeamKeyManager:
    """Manage multiple API keys with per-user tracking."""

    def __init__(self, config_path=None):
        self._keys = {}
        self._usage = defaultdict(lambda: {
            "solves": 0, "cost": 0.0,
            "daily_solves": 0, "daily_reset": time.time(),
        })
        self._lock = threading.Lock()

        if config_path:
            self._load_config(config_path)

    def add_user(self, user_id, api_key, daily_limit=500):
        """Register a user with their API key and limits."""
        self._keys[user_id] = {
            "key": api_key,
            "daily_limit": daily_limit,
            "active": True,
        }

    def get_key(self, user_id):
        """Get API key for a user, enforcing limits."""
        with self._lock:
            if user_id not in self._keys:
                raise ValueError(f"User {user_id} not registered")

            user = self._keys[user_id]
            if not user["active"]:
                raise PermissionError(f"User {user_id} is deactivated")

            usage = self._usage[user_id]

            # Reset daily counter
            if time.time() - usage["daily_reset"] > 86400:
                usage["daily_solves"] = 0
                usage["daily_reset"] = time.time()

            # Check daily limit
            if usage["daily_solves"] >= user["daily_limit"]:
                raise QuotaExceeded(
                    f"User {user_id} daily limit reached ({user['daily_limit']})"
                )

            return user["key"]

    def record_solve(self, user_id, cost=0.003):
        """Record a successful solve for a user."""
        with self._lock:
            self._usage[user_id]["solves"] += 1
            self._usage[user_id]["cost"] += cost
            self._usage[user_id]["daily_solves"] += 1

    def get_user_stats(self, user_id):
        """Get usage statistics for a user."""
        with self._lock:
            return dict(self._usage[user_id])

    def get_team_report(self):
        """Get usage report for all users."""
        with self._lock:
            report = {}
            for user_id, usage in self._usage.items():
                report[user_id] = {
                    "total_solves": usage["solves"],
                    "total_cost": f"${usage['cost']:.4f}",
                    "daily_solves": usage["daily_solves"],
                    "daily_limit": self._keys.get(user_id, {}).get("daily_limit", "N/A"),
                }
            return report

    def deactivate_user(self, user_id):
        """Disable a user's access."""
        if user_id in self._keys:
            self._keys[user_id]["active"] = False

    def _load_config(self, config_path):
        """Load team config from file."""
        with open(config_path, "r") as f:
            config = json.load(f)
        for user in config.get("users", []):
            self.add_user(
                user["id"],
                user["api_key"],
                user.get("daily_limit", 500),
            )


class QuotaExceeded(Exception):
    pass

Usage with Team Manager

import requests
import time


class TeamSolver:
    """CAPTCHA solver with team key management."""

    def __init__(self, key_manager):
        self.keys = key_manager

    def solve(self, user_id, params):
        """Solve CAPTCHA on behalf of a user."""
        api_key = self.keys.get_key(user_id)  # Checks limits

        data = {"key": api_key, "json": 1, **params}
        resp = requests.post(
            "https://ocr.captchaai.com/in.php", data=data, timeout=30,
        )
        result = resp.json()

        if result.get("status") != 1:
            raise RuntimeError(result.get("request"))

        task_id = result["request"]

        time.sleep(10)
        for _ in range(24):
            resp = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": api_key, "action": "get",
                "id": task_id, "json": 1,
            }, timeout=15)
            data = resp.json()

            if data.get("status") == 1:
                self.keys.record_solve(user_id)
                return data["request"]
            if data["request"] != "CAPCHA_NOT_READY":
                raise RuntimeError(data["request"])
            time.sleep(5)

        raise TimeoutError("Solve timeout")


# Setup
manager = TeamKeyManager()
manager.add_user("alice", os.environ["CAPTCHAAI_KEY_ALICE"], daily_limit=1000)
manager.add_user("bob", os.environ["CAPTCHAAI_KEY_BOB"], daily_limit=500)
manager.add_user("ci_pipeline", os.environ["CAPTCHAAI_KEY_CI"], daily_limit=200)

solver = TeamSolver(manager)

# Each user solves with their own limits
token = solver.solve("alice", {
    "method": "userrecaptcha",
    "googlekey": "SITEKEY",
    "pageurl": "https://example.com",
})

Configuration File Format

{
  "users": [
    {
      "id": "alice",
      "api_key": "ENV:CAPTCHAAI_KEY_ALICE",
      "daily_limit": 1000,
      "role": "admin"
    },
    {
      "id": "bob",
      "api_key": "ENV:CAPTCHAAI_KEY_BOB",
      "daily_limit": 500,
      "role": "user"
    },
    {
      "id": "ci_pipeline",
      "api_key": "ENV:CAPTCHAAI_KEY_CI",
      "daily_limit": 200,
      "role": "service"
    }
  ]
}

Note: Use environment variable references (e.g., ENV:VARIABLE_NAME) instead of hardcoding keys in config files.


Team Reporting

def print_team_report(manager):
    """Print formatted team usage report."""
    report = manager.get_team_report()

    print(f"{'User':<20} {'Solves':>8} {'Cost':>10} {'Daily':>8} {'Limit':>8}")
    print("-" * 60)

    total_solves = 0
    total_cost = 0.0

    for user_id, stats in report.items():
        solves = stats["total_solves"]
        cost = float(stats["total_cost"].replace("$", ""))
        daily = stats["daily_solves"]
        limit = stats["daily_limit"]

        print(f"{user_id:<20} {solves:>8} ${cost:>9.4f} {daily:>8} {limit:>8}")
        total_solves += solves
        total_cost += cost

    print("-" * 60)
    print(f"{'TOTAL':<20} {total_solves:>8} ${total_cost:>9.4f}")

FAQ

Should each team member have their own CaptchaAI account?

For teams under 5, a shared account with usage tracking works. For larger teams, separate accounts provide better billing isolation and individual API keys.

How do I prevent one team member from overspending?

Set daily limits per user via the TeamKeyManager. When a user hits their limit, the system blocks additional solves until the next day.

Can I track which project each solve belongs to?

Yes. Add a project_id parameter to the record_solve method and include it in your audit logs for per-project cost allocation.



Scale CaptchaAI across your team — get started.

Discussions (0)

No comments yet.