Authentication
Two methods to authenticate with the Staffify API. Both are equivalent -- use whichever fits your HTTP client.
Method 1: Bearer token
Set the Authorization header with your API key prefixed by Bearer .
curl https://api.staffifyai.com/v1/agents \ -H "Authorization: Bearer sfy_live_YOUR_KEY"
Method 2: X-Api-Key header
Some HTTP clients make it easier to pass a custom header instead of an Authorization header.
curl
curl https://api.staffifyai.com/v1/agents \ -H "X-Api-Key: sfy_live_YOUR_KEY"
API key types
| Feature | Project Key (sfy_live_*) | Org Key (sfy_org_*) |
|---|---|---|
| Scope | One project | All projects in org |
| Create agents | Yes | Yes (with X-Project-Id) |
| Manage projects | No | Yes |
| Recommended for | Production apps | Admin scripts / CI |
Create keys at console.staffifyai.com under Project → API Keys.
Keys are formatted as a prefix (sfy_live_ or sfy_org_) followed by 48 random hex characters. A key that does not start with one of these prefixes is rejected immediately with 401 INVALID_API_KEY without counting against the brute-force limit.
Using org keys with X-Project-Id
Org keys operate at the org level by default. Add an X-Project-Id header to scope the request to a specific project, exactly as a project key would.
curl https://api.staffifyai.com/v1/agents \ -H "Authorization: Bearer sfy_org_YOUR_ORG_KEY" \ -H "X-Project-Id: proj_00000001"
Key scopes
full
Read and write access to all endpoints.
read
GET requests only. Write operations return 403 READ_ONLY_KEY. Use for analytics dashboards, monitoring tools, or any integration that only needs to read data.
Rate limits
Limits are per-organization, per-minute. Enterprise accounts are uncapped (no rate limiting applied). Limits by tier: PAYG 300 req/min, Starter 600 req/min, Growth 1,200 req/min. For non-Enterprise accounts these headers are present on every response:
| Header | Example | Description |
|---|---|---|
| X-RateLimit-Limit | 300 / 600 / 1200 | Requests allowed this minute (PAYG / Starter / Growth). Absent for Enterprise. |
| X-RateLimit-Remaining | 297 | Requests left in this window |
| X-RateLimit-Reset | 1748908260 | Unix epoch when the window resets |
| X-Concurrent-Call-Limit | 10 | Max simultaneous active calls |
| X-RateLimit-Tier | payg | Your account tier |
Enterprise accounts skip rate limiting. Only X-RateLimit-Tier and X-Concurrent-Call-Limit are set; X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset are omitted for enterprise.
When exceeded:
HTTP 429
{
"error": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"retryAfter": 43
}Security best practices
- ✓Never expose API keys in client-side JavaScript or public repositories
- ✓Use environment variables: process.env.STAFFIFY_API_KEY
- ✓Create separate keys per environment (dev / staging / prod)
- ✓Use read-only keys where write access is not needed
- ✓Rotate keys immediately if compromised -- revoke from console, create a new one
- ✓Repeated failed authentication attempts from the same IP are blocked automatically (100 failures per 15-minute window triggers 429 AUTH_RATE_LIMITED)
Authentication error codes
| Code | HTTP | Meaning |
|---|---|---|
| MISSING_API_KEY | 401 | No Authorization header or X-Api-Key header found |
| INVALID_API_KEY | 401 | Key not found, revoked, or malformed |
| INSUFFICIENT_CREDITS | 402 | Account paused due to zero credits. Enterprise accounts are not subject to the credit pause -- PAYG, Starter, and Growth accounts are paused when the balance reaches zero. |
| READ_ONLY_KEY | 403 | Write operation attempted with a read-only key |
| ORG_KEY_REQUIRED | 403 | Endpoint requires an org-level key |
| PROJECT_NOT_FOUND | 404 | X-Project-Id header points to unknown project |
| RATE_LIMIT_EXCEEDED | 429 | Per-minute request limit exceeded |
| AUTH_RATE_LIMITED | 429 | Too many failed authentication attempts from this IP |