Organizations & Projects
Your Staffify account is an organization. Within it you create one or more projects to separate environments (e.g. production vs staging) or customers. Each project has its own agents, phone numbers, and API keys.
Requires org-level key (sfy_org_*)
/v1/org/projectsList all projects in the org
/v1/org/projectsCreate a new project
/v1/org/projects/:projectIdGet a project by public_id or numeric id
/v1/org/projects/:projectIdDelete a project (204, immediately invalidates all its keys)
/v1/org/projects/:projectId/api-keysList API keys for a project
/v1/org/projects/:projectId/api-keysCreate a project API key (raw key shown once)
/v1/org/projects/:projectId/api-keys/:keyIdRevoke a project API key (204)
/v1/org/api-keysList all org-level keys
/v1/org/api-keys/:keyIdRevoke an org-level key (400 if revoking current key)
Requires project-level key (sfy_live_*)
/v1/projectGet the current project
/v1/projectUpdate project name or description
The project object
Org-level endpoints (/v1/org/projects/*) include an additional internal_id field (numeric). Project-level responses (/v1/project) omit it.
// Returned by GET /v1/org/projects and GET /v1/org/projects/:id
{
"id": "proj_a1b2c3d4e5f6a7b8",
"internal_id": 42,
"name": "Production",
"description": "Main production environment",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-15T12:00:00Z"
}
// Returned by GET /v1/project (project-key endpoint)
{
"id": "proj_a1b2c3d4e5f6a7b8",
"name": "Production",
"description": "Main production environment",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-15T12:00:00Z"
}/v1/org/projectsReturns all projects in the org, ordered by creation date (newest first).
curl "https://api.staffifyai.com/v1/org/projects" \
-H "Authorization: Bearer sfy_org_YOUR_ORG_KEY"
# Response
{
"projects": [
{ "id": "proj_a1b2c3d4e5f6a7b8", "internal_id": 1, "name": "Production", "description": null, ... },
{ "id": "proj_b2c3d4e5f6a7b8c9", "internal_id": 2, "name": "Staging", "description": "Testing env", ... }
]
}/v1/org/projects| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Project display name | |
| description | string | optional | Optional description |
curl -X POST https://api.staffifyai.com/v1/org/projects \
-H "Authorization: Bearer sfy_org_YOUR_ORG_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Staging", "description": "Pre-production testing" }'
# Response 201
{
"id": "proj_b2c3d4e5f6a7b8c9",
"internal_id": 2,
"name": "Staging",
"description": "Pre-production testing",
"created_at": "2026-06-03T10:00:00Z",
"updated_at": "2026-06-03T10:00:00Z"
}/v1/org/projects/:projectIdcurl -X DELETE https://api.staffifyai.com/v1/org/projects/proj_b2c3d4e5f6a7b8c9 \ -H "Authorization: Bearer sfy_org_YOUR_ORG_KEY" # Response 204 (no body)
/v1/org/projects/:projectId/api-keys| Field | Type | Required | Description |
|---|---|---|---|
| name | string | optional | Label for this key (default: "Default") |
| scope | string | optional | "full" (read+write) or "read" (GET only, 403 on writes). Default: "full" |
curl -X POST https://api.staffifyai.com/v1/org/projects/proj_a1b2c3d4e5f6a7b8/api-keys \
-H "Authorization: Bearer sfy_org_YOUR_ORG_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "CI Pipeline", "scope": "read" }'
# Response 201
{
"id": 42,
"name": "CI Pipeline",
"scope": "read",
"key": "sfy_live_a1b2c3d4e5f6...",
"key_hint": "...e5f6a7b8",
"created_at": "2026-06-03T10:00:00Z"
}/v1/org/projects/:projectId/api-keysReturns all keys for the project. The raw key is never returned -- only the key_hint (last 8 chars).
# Response
{
"api_keys": [
{
"id": 42,
"name": "CI Pipeline",
"scope": "read",
"key_hint": "...e5f6a7b8",
"last_used_at": "2026-06-03T09:00:00Z",
"created_at": "2026-01-01T00:00:00Z",
"revoked_at": null
}
]
}/v1/org/projects/:projectId/api-keys/:keyIdImmediately revokes a project API key. Any requests using the revoked key will get 401. Returns 204 on success.
curl -X DELETE https://api.staffifyai.com/v1/org/projects/proj_a1b2c3d4e5f6a7b8/api-keys/42 \ -H "Authorization: Bearer sfy_org_YOUR_ORG_KEY" # Response 204 (no body)
Org-level key self-management
You can list and revoke org-level keys using an existing org key. You cannot revoke the key currently making the request.
List org keys
curl "https://api.staffifyai.com/v1/org/api-keys" \
-H "Authorization: Bearer sfy_org_YOUR_ORG_KEY"
# Response
{
"api_keys": [
{ "id": 1, "name": "Primary", "key_hint": "...a1b2c3d4", "last_used_at": "...", "created_at": "..." }
]
}Revoke an org key (400 if you try to revoke the key making this request)
curl -X DELETE https://api.staffifyai.com/v1/org/api-keys/1 \ -H "Authorization: Bearer sfy_org_YOUR_ORG_KEY" # Response 204
Project self-reference (/v1/project)
A project-level key (sfy_live_*) can read and update its own project via /v1/project. Useful for verifying configuration or updating the project name without an org key.
curl "https://api.staffifyai.com/v1/project" \
-H "Authorization: Bearer sfy_live_YOUR_KEY"
# Response
{
"id": "proj_a1b2c3d4e5f6a7b8",
"name": "Production",
"description": null,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-15T12:00:00Z"
}curl -X PATCH https://api.staffifyai.com/v1/project \
-H "Authorization: Bearer sfy_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Production EU", "description": "EU region deployment" }'For project-level webhook config, see the Webhooks page.
Multi-tenant pattern
If you are building an app where each customer gets their own isolated environment, create a project per customer with your org key, then issue a project key for that customer.
Node.js — provision a customer
const ORG_KEY = process.env.STAFFIFY_ORG_KEY;
const BASE = 'https://api.staffifyai.com/v1';
async function provisionCustomer(customerId, customerName) {
// 1. Create project
const project = await fetch(`${BASE}/org/projects`, {
method: 'POST',
headers: { Authorization: `Bearer ${ORG_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name: customerName }),
}).then(r => r.json());
// 2. Create API key for this project
const { key } = await fetch(`${BASE}/org/projects/${project.id}/api-keys`, {
method: 'POST',
headers: { Authorization: `Bearer ${ORG_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ name: `${customerName} key` }),
}).then(r => r.json());
// 3. Store key in your DB (never store in plaintext in prod!)
await db.customers.update(customerId, {
staffify_project_id: project.id,
staffify_api_key: encrypt(key),
});
return project.id;
}