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
Navigate to 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_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0tImportant
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_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0tComponents:
- Prefix:
pgs_live_(production) orpgs_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:
| Scope | Description | Actions |
|---|---|---|
projects:read | View projects | List projects, get project details |
projects:write | Modify projects | Create, update, delete projects |
migrations:run | Analyze & squash | Upload files, run analysis, download results |
usage:read | Check limits | View usage statistics and limits |
admin:read | View admin data | Access admin dashboard (admin only) |
admin:write | Modify settings | Change organization settings (admin only) |
Example Scope Configurations
Minimal permissions for automated builds:
✓ migrations:run
✓ projects:read
✗ projects:write
✗ admin:writeRead-only access for monitoring:
✓ projects:read
✓ usage:read
✗ migrations:run
✗ admin:writeFull administrative access:
✓ projects:read
✓ projects:write
✓ migrations:run
✓ admin:read
✓ admin:writeUsing 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... myappCode 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:
| Plan | Requests/Hour | Burst Limit |
|---|---|---|
| Professional | 1,000 | 100 |
| Agency | 5,000 | 500 |
| Enterprise | Custom | Custom |
Rate Limit Headers
All API responses include rate limit information:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 998
X-RateLimit-Reset: 1729450800Handling 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:
- Navigate to API Keys page
- Find the compromised key
- Click "Regenerate"
- Copy the new key immediately
- 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:
- Navigate to API Keys page
- Find the key to delete
- Click "Delete"
- 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:
- Generate API key in CAPYSQUASH with
migrations:runscope - Add to GitHub repository secrets as
CAPYSQUASH_API_KEY - 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:
- Generate API key in CAPYSQUASH
- Add to GitLab CI/CD Variables as
CAPYSQUASH_API_KEY - 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:
- Generate API key in CAPYSQUASH
- 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:
- Verify the API key is correct (no typos, spaces, or newlines)
- Check if the key exists in your dashboard
- Ensure the key hasn't expired
- Confirm the environment variable is properly set
403 Forbidden
Cause: Insufficient permissions (missing required scope)
Solutions:
- Check if the key has the required scope for the endpoint
- Regenerate the key with correct scopes
- Contact your organization admin for elevated permissions
429 Rate Limited
Cause: Too many requests within the rate limit window
Solutions:
- Wait for the rate limit to reset (check
X-RateLimit-Resetheader) - Implement exponential backoff in your code
- Optimize API usage to reduce unnecessary calls
- 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?