Skip to main content
Docs/API Reference/Organizations & Projects
API Reference

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.

Two key types, two scopes

sfy_org_*

Org-level key. Required for all /v1/org/ endpoints. Use X-Project-Id header to scope resource operations to a specific project. Create and manage these keys in the console.

sfy_live_*

Project-level key. Used for all agent/call/KB operations within a single project. Created via POST /v1/org/projects/:id/api-keys or the console.

Requires org-level key (sfy_org_*)

GET
/v1/org/projects

List all projects in the org

POST
/v1/org/projects

Create a new project

GET
/v1/org/projects/:projectId

Get a project by public_id or numeric id

DELETE
/v1/org/projects/:projectId

Delete a project (204, immediately invalidates all its keys)

GET
/v1/org/projects/:projectId/api-keys

List API keys for a project

POST
/v1/org/projects/:projectId/api-keys

Create a project API key (raw key shown once)

DELETE
/v1/org/projects/:projectId/api-keys/:keyId

Revoke a project API key (204)

GET
/v1/org/api-keys

List all org-level keys

DELETE
/v1/org/api-keys/:keyId

Revoke an org-level key (400 if revoking current key)

Requires project-level key (sfy_live_*)

GET
/v1/project

Get the current project

PATCH
/v1/project

Update 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"
}
GET/v1/org/projects

Returns 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", ... }
  ]
}
POST/v1/org/projects
FieldTypeRequiredDescription
namestringrequiredProject display name
descriptionstringoptionalOptional 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"
}
DELETE/v1/org/projects/:projectId
Destructive. Deleting a project immediately and permanently invalidates all its API keys. Agents, calls, and knowledge bases are also deleted. This cannot be undone.
curl -X DELETE https://api.staffifyai.com/v1/org/projects/proj_b2c3d4e5f6a7b8c9 \
  -H "Authorization: Bearer sfy_org_YOUR_ORG_KEY"

# Response 204 (no body)
POST/v1/org/projects/:projectId/api-keys
The raw key is returned once only in the key field. Store it immediately -- it cannot be retrieved again. Maximum 10 active keys per project.
FieldTypeRequiredDescription
namestringoptionalLabel for this key (default: "Default")
scopestringoptional"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"
}
GET/v1/org/projects/:projectId/api-keys

Returns 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
    }
  ]
}
DELETE/v1/org/projects/:projectId/api-keys/:keyId

Immediately 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;
}
Organizations & Projects - Staffify API