GET
/admin/spaces/{spaceId}/projects
List projects in a space

Returns Projects the caller can access within the Space: every Project if they have any Space-level role, or only the Projects they've been directly added to (accessSource: "project") if they have no Space membership at all. Returns 404 if the caller has neither Space-level nor any Project-level access to this Space.

Example response

{
  "projects": [
    {
      "id": 1,
      "name": "Mobile App",
      "locale": "en",
      "role": "admin",
      "accessSource": "space",
      "templateRecordCount": 0,
      "createdAt": "2026-01-01T00:00:00.000Z"
    }
  ]
}
POST
/admin/spaces/{spaceId}/projects
Create a project

Creates a new Project within the Space. Requires Space owner, admin, or member - a viewer receives 403. Rejected with 409 if the Space's current plan's max_projects limit is already reached. locale is optional - if omitted, it defaults to the parent Space's current locale at the moment of creation (a one-time default, not a live link back to the Space - changing the Space's locale later never changes an already-created Project's locale). See Locales docs for every supported code.

Request

{
  "name": "Mobile App",
  "description": "Backend for the mobile app",
  "locale": "de"
}

Response (201)

{
  "id": 1,
  "spaceId": 1,
  "name": "Mobile App",
  "description": "Backend for the mobile app",
  "locale": "de",
  "createdAt": "2026-01-01T00:00:00.000Z"
}

Returns 422 if locale is provided but isn't one of the supported codes.

GET
/admin/projects/{projectId}
Get a project

Returns Project configuration summary, including the caller's effective role (the greater of their Space-inherited role and any direct Project membership) and resource counts. Returns 404 if the caller has no access at all - Space-level or Project-direct.

Example response

{
  "id": 1,
  "spaceId": 1,
  "name": "Mobile App",
  "description": "Backend for the mobile app",
  "locale": "de",
  "effectiveRole": "admin",
  "templateRecordCount": 0,
  "apiKeyCount": 0,
  "createdAt": "2026-01-01T00:00:00.000Z",
  "updatedAt": "2026-01-01T00:00:00.000Z"
}
PATCH
/admin/projects/{projectId}
Update a project

Updates name, description, and/or locale. Requires an effective Project role of admin. Does not regenerate template data, reset API-key datasets, or change routes/keys - changing locale only affects the next generate/regenerate call, it never rewrites existing template data.

Request

{
  "name": "Mobile App v2",
  "locale": "ja"
}

Response

{
  "id": 1,
  "name": "Mobile App v2",
  "description": "Backend for the mobile app",
  "locale": "ja",
  "updatedAt": "2026-01-01T00:00:00.000Z"
}

Returns 422 if locale isn't one of the supported codes.

DELETE
/admin/projects/{projectId}
Delete a project

Permanently deletes the Project and everything it owns - types, relationships, routes, template/runtime data, API keys, and Project membership/invitations. Requires Space owner or admin (not merely Project admin), since this is a destructive Space-level action.

GET
/admin/projects/{projectId}/members
List direct project members

Returns only users explicitly assigned to the Project - it does not duplicate Space members, who already inherit access. See Spaces docs for how Space-level and direct Project access combine into an effective role. Requires an effective Project role of admin (whether from Project admin membership or an inherited Space admin/owner role) - other roles receive 403.

Example response

{
  "members": [
    {
      "user": {
        "id": 1002,
        "name": "Jane Doe",
        "email": "jane@example.com"
      },
      "role": "editor",
      "source": "project",
      "joinedAt": "2026-01-01T00:00:00.000Z"
    }
  ]
}
POST
/admin/projects/{projectId}/invitations
Invite a user to a project

Grants access to one Project only, without Space-wide access - the preferred way to bring in a contractor, tester, or partner who should only see one Project. Requires effective Project admin. role must be admin, editor, or viewer. Rejected with 409 if the invitee already has equal or greater access through Space membership, or is already a direct member. Expires after 7 days - the same background sweep described on the Spaces docs page flips a stale pending invitation to expired automatically.

Request

{
  "email": "contractor@example.com",
  "role": "editor"
}

Response (201)

{
  "id": 1,
  "email": "contractor@example.com",
  "scope": "project",
  "projectId": 1,
  "role": "editor",
  "status": "pending",
  "expiresAt": "2026-01-08T00:00:00.000Z",
  "token": ""
}
GET
/admin/projects/{projectId}/invitations
List project invitations

Returns every invitation ever issued for this Project, most recent first, regardless of status - the same audit view as the Spaces docs' invitation list. Requires effective Project admin, the same bar as issuing one. Never includes the raw or hashed token.

Example response

{
  "invitations": [
    {
      "id": 1,
      "email": "contractor@example.com",
      "scope": "project",
      "projectId": 1,
      "role": "editor",
      "status": "pending",
      "invitedBy": {
        "id": 1001,
        "name": "Jane Doe",
        "email": "jane@example.com"
      },
      "expiresAt": "2026-01-08T00:00:00.000Z",
      "createdAt": "2026-01-01T00:00:00.000Z"
    }
  ]
}
DELETE
/admin/projects/{projectId}/invitations/{invitationId}
Cancel an invitation

Cancels a still-pending Project invitation - the same behaviour as the Spaces docs' cancel endpoint, at the same effective Project admin bar as issuing one. Returns 404 for an invitation that doesn't exist, belongs to a different Project, or isn't pending anymore.

PATCH
/admin/projects/{projectId}/members/{userId}
Change a direct member's role

Changes only the direct Project membership record - it cannot reduce access inherited from the Space (a user who is also a Space admin keeps that access regardless of what this sets). Requires effective Project admin.

Response

{
  "userId": 1002,
  "projectId": 1,
  "role": "admin",
  "updatedAt": "2026-01-01T00:00:00.000Z"
}
DELETE
/admin/projects/{projectId}/members/{userId}
Remove a direct project member

Removes explicit Project membership. If the user retains access through Space membership, that access continues unaffected. Otherwise, their personal API keys for this Project are revoked - shared keys are untouched, since they belong to the Project rather than the departing user.