Skip to content

Organizations and websites

The organization is the tenant root. It owns members (each with a role), websites, and an entitlement plan. Every operational and knowledge row scopes back to one organization, directly or through one of its websites.

The hierarchy

organization
  ├── members        (user + role: viewer / editor / organization_admin / organization_owner)
  ├── entitlements   (plan: free / advanced)
  └── websites
        ├── verification   (ownership proof + trust tier)
        ├── connectors     (ingestion tokens)
        └── knowledge      (the graph -> published node)

Registering a user creates an organization in the same call; the registrant becomes its organization_owner. A user can also create additional organizations, becoming the owner of each.

Roles and permissions

Roles form an ordered ladder. A higher role includes every permission of the roles below it. Roles are per organization (admin and super_admin are platform-wide).

Permissionviewereditororganization_adminorganization_owner
Read organization, websites, knowledge, entitlementsyesyesyesyes
Edit a website, request verification, trigger publishyesyesyes
Create a websiteyesyes
Manage members (add, change role, remove)yesyes
Issue and rotate connector tokensyesyes
Edit organization settingsyesyes
Delete the organizationyes
Run GDPR erasure of the organizationyes

The minimum role for each route is enforced in the service layer, which derives the caller's effective role from org_membership. See Authentication for the full ladder including the platform roles.

Organization endpoints

apps/api/src/modules/organization/router.ts. Every route requires a user; the service enforces per-org RBAC and tenant scope.

MethodPathMin role
GET/v1/organizationsviewer (member)
POST/v1/organizationsany user (caller becomes owner)
GET/v1/organizations/:idmember
PATCH/v1/organizations/:idorganization_admin
DELETE/v1/organizations/:idorganization_owner
GET/v1/organizations/:id/membersmember
POST/v1/organizations/:id/membersorganization_admin
PATCH/v1/organizations/:id/members/:userIdorganization_admin
DELETE/v1/organizations/:id/members/:userIdorganization_admin
POST/v1/organizations/:id/eraseorganization_owner

POST /v1/organizations/:id/erase is GDPR Article 17 hard-erasure. It requires a typed confirmation matching the organization slug or name and returns 202.

Errors: validation.failed, auth.tenant_mismatch, auth.forbidden, privacy.erasure_forbidden, privacy.subject_not_found, privacy.erasure_in_progress, internal.error.

bash
# Create an organization (caller becomes owner)
curl -sS -X POST https://api.bainquet.online/v1/organizations \
  -H "Authorization: Bearer $ACCESS_JWT" \
  -H 'Content-Type: application/json' \
  -d '{ "name": "Acme" }'

# Add a member as editor
curl -sS -X POST https://api.bainquet.online/v1/organizations/$ORG_ID/members \
  -H "Authorization: Bearer $ACCESS_JWT" \
  -H 'Content-Type: application/json' \
  -d '{ "email": "teammate@acme.com", "role": "editor" }'

Website endpoints

apps/api/src/modules/website/router.ts. Websites are created under an organization.

MethodPathMin role
GET/v1/organizations/:orgId/websitesviewer
POST/v1/organizations/:orgId/websitesorganization_admin
GET/v1/websites/:idviewer
PATCH/v1/websites/:ideditor
DELETE/v1/websites/:idorganization_admin

Errors: validation.failed, auth.tenant_mismatch, auth.forbidden, website.not_found.

bash
# List websites in an organization
curl -sS https://api.bainquet.online/v1/organizations/$ORG_ID/websites \
  -H "Authorization: Bearer $ACCESS_JWT"

# Create a website
curl -sS -X POST https://api.bainquet.online/v1/organizations/$ORG_ID/websites \
  -H "Authorization: Bearer $ACCESS_JWT" \
  -H 'Content-Type: application/json' \
  -d '{ "domain": "example.com", "name": "Example" }'

After creating a website, verify its ownership (Verifying ownership) before issuing a connector token and publishing.

Tenant isolation

Cross-tenant access is blocked: a read of another organization's resource returns 404 (so existence is not leaked), and a mutation returns 403. Every knowledge query is WHERE website_id = $1.

Entitlements and usage

Plan capabilities and usage are read-only endpoints under billing.

MethodPathMin role
GET/v1/organizations/:id/entitlementsorg member (scoped)
GET/v1/organizations/:id/usageorg member (scoped)

These return plan-derived constants and usage counters. See Free vs AI-enhanced for what each plan includes.

API keys, transfer, and webhooks

These management surfaces are available (organization_admin+, except transfer which is owner-gated):

  • API keys: POST / GET /v1/organizations/:id/api-keys, DELETE /v1/organizations/:id/api-keys/:keyId. The bnq_live_* secret is shown once.
  • Organization transfer: POST /v1/organizations/:id/transfer (owner initiates to a target email), POST /v1/organizations/transfers/:token/accept (recipient accepts), POST /v1/organizations/:id/transfer/cancel.
  • Website transfer: POST /v1/websites/:id/transfer moves a website to another org the caller owns.
  • Webhooks: POST / GET /v1/websites/:id/webhooks, PATCH / DELETE /v1/websites/:id/webhooks/:webhookId. The signing secret is shown once.

Owner-controlled structured data for AI.