> ## Documentation Index
> Fetch the complete documentation index at: https://docs.promptguard.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Managing Projects

> Organize your applications with PromptGuard projects

## What are Projects?

Projects are how you organize different environments or applications in PromptGuard. Each project has:

* **Separate API keys** - Isolate credentials per environment
* **Independent usage tracking** - Monitor each project's requests separately
* **Dedicated security settings** - Configure policies per project
* **Individual analytics** - View metrics for each project

## Common Project Structures

### By Environment

```
Production       - Live application
Staging          - Pre-production testing
Development      - Local development
```

### By Application

```
Customer Portal  - Customer-facing chatbot
Admin Dashboard  - Internal AI tools
Mobile App       - iOS/Android application
```

### By Team

```
Marketing Team   - Marketing automation
Sales Team       - Sales assistant
Engineering      - Code review assistant
```

## Creating Your First Project

When you sign up for PromptGuard, a **"Production"** project is automatically created for you. This ensures you can start using PromptGuard immediately.

### Creating Additional Projects

1. Navigate to **Projects** in the dashboard
2. Click **"Create Project"**
3. Enter project details:
   * **Name**: Descriptive name (e.g., "Staging", "Mobile App")
   * **Description**: Optional context about the project
4. Click **"Create Project"**

Your new project is ready! Now you can create API keys for it.

## Creating API Keys

Each project can have multiple API keys (e.g., different services, rotating keys):

1. **Select your project** from the project selector in the header
2. Navigate to **API Keys**
3. Click **"Create API Key"**
4. Enter details:
   * **Name**: Descriptive name (e.g., "Backend API", "Cron Jobs")
5. Click **"Create API Key"**

<Warning>
  **Save the API key immediately!** It's only shown once during creation. If you lose it, you'll need to create a new key.
</Warning>

## Switching Between Projects

Use the **project selector** in the dashboard header to quickly switch between projects:

1. Click the project name in the header
2. Select a different project from the dropdown
3. All pages (Analytics, API Keys, etc.) automatically update to show the selected project's data

<Tip>
  The project selector remembers your last selection, so you'll return to the same project next time you visit the dashboard.
</Tip>

## Project URLs

Each project has its own dedicated URLs:

```
/dashboard/projects/{project-id}/overview
/dashboard/projects/{project-id}/analytics
/dashboard/projects/{project-id}/api-keys
```

These URLs are **shareable** - you can bookmark or send teammates links to specific projects.

## Viewing All Projects

Navigate to **Projects** in the dashboard to see all your projects at once:

* **Project statistics** - Requests, flagged count, last activity
* **Time filtering** - View stats for last 7/30/90 days
* **Search projects** - Quickly find projects by name
* **Create/delete projects** - Manage your project portfolio

## Deleting Projects

<Warning>
  **Cannot delete your last project!** You must always have at least one project. This prevents accidental lockout from the platform.
</Warning>

To delete a project:

1. Go to **Projects** page
2. Click the **delete icon** next to the project
3. Confirm deletion

**What happens when you delete a project:**

* All API keys are immediately revoked
* Historical data is preserved for 30 days
* Active requests will fail
* Cannot be undone

<Tip>
  Instead of deleting, consider renaming the project or archiving it (coming soon).
</Tip>

## Per-Project Token Limits

Control LLM costs by setting a maximum token count per request on any project. Requests exceeding the limit are rejected with HTTP 413 before reaching the LLM provider - saving you money on runaway prompts.

### Setting a Token Limit

Configure via the dashboard (**Project → Settings → Token Limit**) or via the database:

```sql theme={"system"}
UPDATE projects SET max_tokens_per_request = 4096
WHERE id = 'proj_abc123';
```

### How It Works

1. PromptGuard estimates the token count of the incoming prompt using [tiktoken](https://github.com/openai/tiktoken) (the same tokenizer OpenAI uses)
2. If the count exceeds `max_tokens_per_request`, the request is rejected immediately
3. The response includes the actual token count so you can adjust

```json theme={"system"}
{
  "error": "token_limit_exceeded",
  "detail": "Request contains ~8,200 tokens, exceeding the project limit of 4,096",
  "token_count": 8200,
  "max_tokens": 4096
}
```

### Token Counting

PromptGuard uses `tiktoken` (OpenAI's tokenizer) for accurate counts. If tiktoken is unavailable, it falls back to a `chars / 4` heuristic. Token limits apply to the full prompt text including system messages.

<Tip>
  Set conservative limits during development (e.g., 2,048) and increase for production. This catches accidentally large prompts early.
</Tip>

## Best Practices

### Use Separate Projects for Each Environment

```
Good: Production, Staging, Development
Bad: One project for everything
```

**Why?** Isolates credentials, prevents accidental production data exposure, enables environment-specific security policies.

### Name Projects Clearly

```
Good: "Production - Customer Portal"
Good: "Staging - Mobile App v2"
Bad: "Project 1", "Test", "New"
```

**Why?** Makes it easy to identify projects in dropdown, avoids confusion in team environments.

### Rotate API Keys Regularly

```
Good: Create new key → Update production → Delete old key
Bad: Use same key for years
```

**Why?** Limits exposure if key is compromised, follows security best practices.

### Use Descriptive API Key Names

```
Good: "Backend API - Server1", "Cron Job - Daily Report"
Bad: "Key 1", "Test", "New Key"
```

**Why?** Makes it easy to identify which key is used where when rotating or debugging.

## Project Limits

| Plan  | Max Projects | Max API Keys per Project |
| ----- | ------------ | ------------------------ |
| Free  | 1            | 1                        |
| Pro   | 5            | 5                        |
| Scale | Unlimited    | Unlimited                |

<Note>
  Need more projects or API keys? [Upgrade your plan](https://app.promptguard.co/billing) or [contact sales](mailto:sales@promptguard.co).
</Note>

## API Access

<Info>
  **Developer API Endpoints**: The project management endpoints below are part of the **Developer API** and are included in the OpenAPI spec. They use API key authentication and are suitable for SDK usage.
</Info>

Projects can be managed programmatically using the Developer API. All endpoints require API key authentication.

### Complete CRUD Operations

<Tabs>
  <Tab title="Python">
    ```python theme={"system"}
    import requests
    import os

    # API key authentication (Developer API)
    api_key = os.environ.get("PROMPTGUARD_API_KEY")
    base_url = "https://api.promptguard.co/api/v1/projects"

    headers = {
        "X-API-Key": api_key,
        "Content-Type": "application/json"
    }

    # CREATE - Create a new project
    def create_project(name, description=None, use_case="default", strictness_level="moderate"):
        payload = {
            "name": name,
            "description": description,
            "use_case": use_case,
            "strictness_level": strictness_level
        }

        response = requests.post(base_url, headers=headers, json=payload)

        if response.status_code == 201:
            project = response.json()
            print(f"Created project: {project['id']}")
            return project
        elif response.status_code == 400:
            error = response.json()
            print(f"Error: {error.get('detail', 'Invalid request')}")
        elif response.status_code == 401:
            print("Error: Authentication required. Please log in.")
        else:
            print(f"Error: HTTP {response.status_code}")
        return None

    # READ - List all projects
    def list_projects():
        response = requests.get(base_url, headers=headers)

        if response.status_code == 200:
            projects = response.json()
            print(f"Found {len(projects)} projects:")
            for project in projects:
                print(f"  - {project['name']} ({project['id']})")
            return projects
        else:
            print(f"Error: HTTP {response.status_code}")
            return []

    # READ - Get single project
    def get_project(project_id):
        url = f"{base_url}/{project_id}"
        response = requests.get(url, headers=headers)

        if response.status_code == 200:
            project = response.json()
            print(f"Project: {project['name']}")
            print(f"  Description: {project.get('description', 'N/A')}")
            print(f"  Use Case: {project.get('use_case', 'default')}")
            print(f"  Strictness: {project.get('strictness_level', 'moderate')}")
            return project
        elif response.status_code == 404:
            print(f"Error: Project {project_id} not found")
        else:
            print(f"Error: HTTP {response.status_code}")
        return None

    # Note: Update endpoint is not available in Developer API
    # To update projects, use the dashboard or delete and recreate

    # DELETE - Delete project
    def delete_project(project_id):
        url = f"{base_url}/{project_id}"
        response = requests.delete(url, headers=headers)

        if response.status_code == 200:
            print(f"Deleted project {project_id}")
            return True
        elif response.status_code == 404:
            print(f"Error: Project {project_id} not found")
        elif response.status_code == 400:
            error = response.json()
            if "last project" in error.get('detail', '').lower():
                print("Error: Cannot delete your last project. Create another project first.")
            else:
                print(f"Error: {error.get('detail', 'Cannot delete project')}")
        else:
            print(f"Error: HTTP {response.status_code}")
        return False

    # Example usage
    if __name__ == "__main__":
        # Create a new project
        project = create_project(
            name="Staging Environment",
            description="Pre-production testing",
            use_case="default",
            strictness_level="moderate"
        )

        if project:
            project_id = project['id']

            # Get project details
            get_project(project_id)

            # Note: Update is not available in Developer API
            # Use dashboard or delete and recreate if needed

            # List all projects
            list_projects()

            # Note: Uncomment to delete (be careful!)
            # delete_project(project_id)
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={"system"}
    import fetch from 'node-fetch';

    const baseUrl = 'https://api.promptguard.co/api/v1/projects';
    const apiKey = process.env.PROMPTGUARD_API_KEY;

    const headers = {
      'X-API-Key': apiKey,
      'Content-Type': 'application/json'
    };

    // CREATE - Create a new project
    async function createProject(
      name: string,
      description?: string,
      useCase: string = 'default',
      strictnessLevel: string = 'moderate'
    ) {
      const payload = {
        name,
        description,
        use_case: useCase,
        strictness_level: strictnessLevel
      };

      const response = await fetch(baseUrl, {
        method: 'POST',
        headers,
        body: JSON.stringify(payload)
      });

      if (response.status === 201) {
        const project = await response.json();
        console.log(`Created project: ${project.id}`);
        return project;
      } else if (response.status === 400) {
        const error = await response.json();
        console.error(`Error: ${error.detail || 'Invalid request'}`);
      } else if (response.status === 401) {
        console.error('Error: Authentication required. Please log in.');
      } else {
        console.error(`Error: HTTP ${response.status}`);
      }
      return null;
    }

    // READ - List all projects
    async function listProjects() {
      const response = await fetch(baseUrl, { headers });

      if (response.status === 200) {
        const projects = await response.json();
        console.log(`Found ${projects.length} projects:`);
        projects.forEach((project: any) => {
          console.log(`  - ${project.name} (${project.id})`);
        });
        return projects;
      } else {
        console.error(`Error: HTTP ${response.status}`);
        return [];
      }
    }

    // READ - Get single project
    async function getProject(projectId: string) {
      const url = `${baseUrl}/${projectId}`;
      const response = await fetch(url, { headers });

      if (response.status === 200) {
        const project = await response.json();
        console.log(`Project: ${project.name}`);
        console.log(`  Description: ${project.description || 'N/A'}`);
        console.log(`  Use Case: ${project.use_case || 'default'}`);
        console.log(`  Strictness: ${project.strictness_level || 'moderate'}`);
        return project;
      } else if (response.status === 404) {
        console.error(`Error: Project ${projectId} not found`);
      } else {
        console.error(`Error: HTTP ${response.status}`);
      }
      return null;
    }

    // Note: Update endpoint is not available in Developer API
    // To update projects, use the dashboard or delete and recreate

    // DELETE - Delete project
    async function deleteProject(projectId: string) {
      const url = `${baseUrl}/${projectId}`;
      const response = await fetch(url, {
        method: 'DELETE',
        headers
      });

      if (response.status === 200) {
        console.log(`Deleted project ${projectId}`);
        return true;
      } else if (response.status === 404) {
        console.error(`Error: Project ${projectId} not found`);
      } else if (response.status === 400) {
        const error = await response.json();
        if (error.detail?.toLowerCase().includes('last project')) {
          console.error('Error: Cannot delete your last project. Create another project first.');
        } else {
          console.error(`Error: ${error.detail || 'Cannot delete project'}`);
        }
      } else {
        console.error(`Error: HTTP ${response.status}`);
      }
      return false;
    }

    // Example usage
    async function main() {
      // Create a new project
      const project = await createProject(
        'Staging Environment',
        'Pre-production testing',
        'default',
        'moderate'
      );

      if (project) {
        const projectId = project.id;

        // Get project details
        await getProject(projectId);

        // Note: Update is not available in Developer API
        // Use dashboard or delete and recreate if needed

        // List all projects
        await listProjects();

        // Note: Uncomment to delete (be careful!)
        // await deleteProject(projectId);
      }
    }

    main();
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"system"}
    # CREATE - Create a new project
    curl -X POST https://api.promptguard.co/api/v1/projects \
      -H "X-API-Key: $PROMPTGUARD_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Staging Environment",
        "description": "Pre-production testing",
        "use_case": "default",
        "strictness_level": "moderate"
      }'

    # READ - List all projects
    curl https://api.promptguard.co/api/v1/projects \
      -H "X-API-Key: $PROMPTGUARD_API_KEY"

    # READ - Get single project
    curl https://api.promptguard.co/api/v1/projects/{project_id} \
      -H "X-API-Key: $PROMPTGUARD_API_KEY"

    # Note: Update endpoint is not available in Developer API
    # To update projects, use the dashboard or delete and recreate

    # DELETE - Delete project
    curl -X DELETE https://api.promptguard.co/api/v1/projects/{project_id} \
      -H "X-API-Key: $PROMPTGUARD_API_KEY"
    ```
  </Tab>
</Tabs>

### Response Formats

**Create Project Response (201 Created)**

```json theme={"system"}
{
  "id": "proj_abc123def456",
  "name": "Staging Environment",
  "description": "Pre-production testing",
  "use_case": "default",
  "strictness_level": "moderate",
  "fail_mode": "open",
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
}
```

**List Projects Response (200 OK)**

```json theme={"system"}
[
  {
    "id": "proj_abc123def456",
    "name": "Production",
    "description": "Live application",
    "use_case": "default",
    "strictness_level": "moderate",
    "created_at": "2024-01-01T00:00:00Z"
  },
  {
    "id": "proj_xyz789ghi012",
    "name": "Staging Environment",
    "description": "Pre-production testing",
    "use_case": "support_bot",
    "strictness_level": "strict",
    "created_at": "2024-01-15T10:30:00Z"
  }
]
```

**Get Project Stats Response (200 OK)**

```json theme={"system"}
{
  "project_id": "proj_abc123def456",
  "stats": {
    "total_requests": 1250,
    "blocked_requests": 23,
    "block_rate": 0.0184,
    "last_activity": "2024-01-15T14:30:00Z"
  },
  "period": {
    "days": 30,
    "start_date": "2023-12-16T00:00:00Z",
    "end_date": "2024-01-15T23:59:59Z"
  }
}
```

**Error Responses**

**400 Bad Request** - Invalid request or project limit reached

```json theme={"system"}
{
  "detail": "Project limit reached. Upgrade your plan to create more projects."
}
```

**401 Unauthorized** - Invalid or missing API key

```json theme={"system"}
{
  "detail": "Invalid API key"
}
```

**404 Not Found** - Project doesn't exist

```json theme={"system"}
{
  "detail": "Project not found"
}
```

**400 Bad Request** - Cannot delete last project

```json theme={"system"}
{
  "detail": "Cannot delete your last project. Create another project first."
}
```

<Info>
  Session tokens are obtained via the login endpoint. See the [Quickstart](/quickstart) for details.
</Info>

## Troubleshooting

### "Cannot create API key"

**Cause:** No project selected or project limit reached.

**Solution:**

1. Ensure a project is selected in the project selector
2. Check your plan's project limits
3. Upgrade if needed

### "API key not working"

**Cause:** API key belongs to wrong project or was deleted.

**Solution:**

1. Verify the API key is correctly set and not empty
2. Check which project the key belongs to
3. Ensure the key hasn't been deleted
4. Create a new key if needed

### "Cannot delete project"

**Cause:** Trying to delete your last project.

**Solution:** You must always have at least one project. Create a new project first, then delete the old one.

## Next Steps

<CardGroup cols={2}>
  <Card title="Create API Keys" icon="key" href="/api-reference/api-keys">
    Learn how to create and manage API keys
  </Card>

  <Card title="View Analytics" icon="chart-line" href="/platform/dashboard">
    Monitor your project's security metrics
  </Card>

  <Card title="Configure Security Rules" icon="shield" href="/security/policy-presets">
    Set up security policies for your project
  </Card>

  <Card title="Team Access" icon="users" href="/platform/organizations">
    Share projects with your team
  </Card>
</CardGroup>
