CAPYSQUASH

API Authentication & Access

Secure API authentication and programmatic access to CAPYSQUASH for automation, CI/CD pipelines, and custom integrations

API Authentication & Access

Automate migration optimization with secure API authentication—perfect for CI/CD pipelines, custom workflows, and enterprise integrations

CAPYSQUASH provides a fully-featured REST API for programmatic access to all platform capabilities. Integrate migration analysis into your development workflow, automate optimization across multiple projects, and build custom tooling on top of our powerful engine.

Plan Availability

API access is available on Professional, Agency, and Enterprise plans. API keys provide secure, scoped access to organization resources without requiring user login.

Why Use the API?

Automation

Integrate CAPYSQUASH into your CI/CD pipeline for automatic migration analysis on every PR

Custom Workflows

Build custom tooling and dashboards tailored to your team's specific needs

Enterprise Ready

Secure authentication with scoped permissions, rate limiting, and usage tracking

Creating API Keys

Go to your Dashboard → Organization Settings → API Keys

You must be an organization admin or owner to create API keys.

Configure Your Key

Provide the following information:

  • Name: Descriptive name (e.g., "CI/CD Pipeline", "Production Dashboard")
  • Description: Optional notes about the key's purpose
  • Scopes: Select permissions (see Key Scopes below)
  • Expiration: Optional expiration date for enhanced security

Follow the principle of least privilege: only grant the scopes your integration actually needs.

Save the Key Securely

Copy the API key immediately—it's shown only once!

pgs_live_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t

Important

Store the key securely in your password manager or environment variables. If lost, you'll need to regenerate a new key.

API Key Format

API keys follow this structure:

pgs_live_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t

Components:

  • Prefix: pgs_live_ (production) or pgs_test_ (sandbox)
  • Key: 40-character securely generated random string
  • Storage: Hashed in database, never stored in plain text

Key Scopes (Permissions)

Control exactly what each API key can access:

ScopeDescriptionActions
projects:readView projectsList projects, get project details
projects:writeModify projectsCreate, update, delete projects
migrations:runAnalyze & squashUpload files, run analysis, download results
usage:readCheck limitsView usage statistics and limits
admin:readView admin dataAccess admin dashboard (admin only)
admin:writeModify settingsChange organization settings (admin only)

Example Scope Configurations

Minimal permissions for automated builds:

✓ migrations:run
✓ projects:read
✗ projects:write
✗ admin:write

Read-only access for monitoring:

✓ projects:read
✓ usage:read
✗ migrations:run
✗ admin:write

Full administrative access:

✓ projects:read
✓ projects:write
✓ migrations:run
✓ admin:read
✓ admin:write

Using API Keys

Authentication Header

Include your API key in the Authorization header with Bearer authentication:

Authorization: Bearer pgs_live_1a2b3c4d5e6f7g8h9i0j...

Environment Variables

Best Practice: Store keys in environment variables, never in source code:

# .env file
CAPYSQUASH_API_KEY=pgs_live_1a2b3c4d5e...
# Shell
export CAPYSQUASH_API_KEY="pgs_live_1a2b3c4d5e..."
# Docker run
docker run -e CAPYSQUASH_API_KEY=pgs_live_1a2b3c4d5e... myapp

Code Examples

const CAPYSQUASH_API_KEY = process.env.CAPYSQUASH_API_KEY;

const response = await fetch('https://api.capysquash.dev/v1/projects', {
  headers: {
    'Authorization': `Bearer ${CAPYSQUASH_API_KEY}`,
    'Content-Type': 'application/json',
  },
});

const projects = await response.json();
console.log(`Found ${projects.total} projects`);
import os
import requests

CAPYSQUASH_API_KEY = os.environ['CAPYSQUASH_API_KEY']

response = requests.get(
    'https://api.capysquash.dev/v1/projects',
    headers={
        'Authorization': f'Bearer {CAPYSQUASH_API_KEY}',
        'Content-Type': 'application/json',
    }
)

projects = response.json()
print(f"Found {projects['total']} projects")
package main

import (
    "fmt"
    "net/http"
    "os"
)

func main() {
    apiKey := os.Getenv("CAPYSQUASH_API_KEY")

    req, _ := http.NewRequest("GET", "https://api.capysquash.dev/v1/projects", nil)
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, _ := client.Do(req)
    // Handle response...
}
curl https://api.capysquash.dev/v1/projects \
  -H "Authorization: Bearer $CAPYSQUASH_API_KEY" \
  -H "Content-Type: application/json"

Rate Limiting

API keys are subject to rate limits based on your plan:

PlanRequests/HourBurst Limit
Professional1,000100
Agency5,000500
EnterpriseCustomCustom

Rate Limit Headers

All API responses include rate limit information:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 998
X-RateLimit-Reset: 1729450800

Handling Rate Limits

Implement exponential backoff when hitting rate limits:

async function makeRequest(url: string) {
  const response = await fetch(url, {
    headers: { 'Authorization': `Bearer ${apiKey}` },
  });

  if (response.status === 429) {
    const resetTime = response.headers.get('X-RateLimit-Reset');
    const waitSeconds = parseInt(resetTime) - Math.floor(Date.now() / 1000);

    console.log(`Rate limited. Retrying after ${waitSeconds} seconds`);
    await new Promise(resolve => setTimeout(resolve, waitSeconds * 1000));

    return makeRequest(url); // Retry
  }

  return response.json();
}
import time
import requests

def make_request(url):
    response = requests.get(url, headers={
        'Authorization': f'Bearer {api_key}'
    })

    if response.status_code == 429:
        reset_time = int(response.headers['X-RateLimit-Reset'])
        wait_seconds = reset_time - int(time.time())

        print(f"Rate limited. Retrying after {wait_seconds} seconds")
        time.sleep(wait_seconds)

        return make_request(url)  # Retry

    return response.json()

Managing API Keys

View All Keys

Access your API keys dashboard to see:

  • Key name and description
  • Scopes (permissions)
  • Created date
  • Last used timestamp
  • Status (active/expired)
  • Usage statistics

Regenerate a Key

If your API key is compromised:

  1. Navigate to API Keys page
  2. Find the compromised key
  3. Click "Regenerate"
  4. Copy the new key immediately
  5. Update all systems using the old key

The old key is immediately revoked upon regeneration. All requests using the old key will fail with 401 Unauthorized.

Delete a Key

Permanently revoke an API key:

  1. Navigate to API Keys page
  2. Find the key to delete
  3. Click "Delete"
  4. Confirm deletion

The key is immediately revoked—all requests will fail instantly.

Key Expiration

Set automatic expiration for enhanced security:

Options:

  • Never expire (default)
  • 30 days
  • 90 days
  • 1 year
  • Custom date

You'll receive an email notification 7 days before expiration.

Security Best Practices

Security Checklist

✓ DO

  • ✓ Store keys in environment variables
  • ✓ Use scoped permissions (least privilege)
  • ✓ Set expiration dates
  • ✓ Monitor key usage regularly
  • ✓ Rotate keys periodically (quarterly)
  • ✓ Use different keys per environment
  • ✓ Delete unused keys immediately

✗ DON'T

  • ✗ Commit keys to version control
  • ✗ Share keys via email/Slack
  • ✗ Use the same key everywhere
  • ✗ Hard-code keys in source code
  • ✗ Give admin scopes to CI/CD keys
  • ✗ Ignore "last used" timestamps

Detecting Compromised Keys

Warning signs:

  • Unexpected requests in activity log
  • Unusual API usage spikes
  • Requests from unexpected IP addresses
  • Scopes being used that shouldn't be active

Immediate action: Regenerate or delete the key immediately.

CI/CD Integration Examples

GitHub Actions

name: Analyze Migrations

on:
  pull_request:
    paths:
      - 'migrations/**'

jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Analyze with CAPYSQUASH
        env:
          CAPYSQUASH_API_KEY: ${{ secrets.CAPYSQUASH_API_KEY }}
        run: |
          curl -X POST https://api.capysquash.dev/v1/analyze \
            -H "Authorization: Bearer $CAPYSQUASH_API_KEY" \
            -F "files=@migrations/001.sql" \
            -F "safety_level=standard"

Setup:

  1. Generate API key in CAPYSQUASH with migrations:run scope
  2. Add to GitHub repository secrets as CAPYSQUASH_API_KEY
  3. Reference in workflow as shown above

GitLab CI

analyze-migrations:
  stage: test
  script:
    - |
      curl -X POST https://api.capysquash.dev/v1/analyze \
        -H "Authorization: Bearer $CAPYSQUASH_API_KEY" \
        -F "files=@migrations/001.sql" \
        -F "safety_level=standard"
  only:
    changes:
      - migrations/**

Setup:

  1. Generate API key in CAPYSQUASH
  2. Add to GitLab CI/CD Variables as CAPYSQUASH_API_KEY
  3. Mark as "Protected" and "Masked"

CircleCI

version: 2.1

jobs:
  analyze:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run:
          name: Analyze Migrations
          command: |
            curl -X POST https://api.capysquash.dev/v1/analyze \
              -H "Authorization: Bearer $CAPYSQUASH_API_KEY" \
              -F "files=@migrations/001.sql"

Setup:

  1. Generate API key in CAPYSQUASH
  2. Add to CircleCI project environment variables as CAPYSQUASH_API_KEY

Troubleshooting

401 Unauthorized

Possible causes:

  • Invalid or missing API key
  • Key has been deleted or revoked
  • Key has expired
  • Environment variable not set

Solutions:

  1. Verify the API key is correct (no typos, spaces, or newlines)
  2. Check if the key exists in your dashboard
  3. Ensure the key hasn't expired
  4. Confirm the environment variable is properly set

403 Forbidden

Cause: Insufficient permissions (missing required scope)

Solutions:

  1. Check if the key has the required scope for the endpoint
  2. Regenerate the key with correct scopes
  3. Contact your organization admin for elevated permissions

429 Rate Limited

Cause: Too many requests within the rate limit window

Solutions:

  1. Wait for the rate limit to reset (check X-RateLimit-Reset header)
  2. Implement exponential backoff in your code
  3. Optimize API usage to reduce unnecessary calls
  4. Upgrade to a higher plan for increased limits

Key Not Working After Creation

Common mistakes:

  • API key copied incorrectly (missing characters)
  • Extra spaces or newlines added when pasting
  • Using pgs_test_ key in production environment
  • Incorrect authorization header format

Fix: Regenerate the key and carefully copy the entire string.

Next Steps

How is this guide?

On this page