Skip to main content

Organizations

An organization is the tenant boundary. Every query in every binary is scoped to the caller's organization, whether they authenticated with a session or an API key.

A fresh account has no organization. Until it creates one, every org-scoped route refuses it:

{ "detail": "organization setup is required before using the app", "needs_org_setup": true }

Create an organization​

POST /api/organization — session required, no organization yet

{
"name": "Pragati AI",
"website": "https://pragati.example",
"employee_count": "11-50",
"company_type": "generic_sales",
"company_type_other": ""
}
Fieldnextneural_intel / nextneural_assistnextneural_converse
namerequiredrequired
employee_countrequiredoptional
company_typerequired, from a fixed listoptional, free text
websiteoptionaloptional
company_type_otheroptionaloptional

company_type accepts a different set of values in each binary:

BinaryAccepted values
nextneural_intelreal_estate, call_center, generic_sales, freelancer, other
nextneural_assistsales_team, customer_support, agency_bpo, saas_company, other
nextneural_conversenot validated

An unrecognised value returns 400 naming the accepted list.

The required fields differ by binary

nextneural_intel and nextneural_assist both reject a body without employee_count and company_type; nextneural_converse accepts name alone. A client that posts the same body to all three will get a 400 from two of them.

Returns the created organization together with a new session token that carries the organization claim — use it in place of the token you signed in with:

{
"organization": {
"id": 1,
"name": "Pragati AI",
"website": "https://pragati.example",
"employee_count": "11-50",
"company_type": "generic_sales",
"company_type_other": null,
"waitlist_status": "allowed"
},
"token": "eyJhbGciOiJIUzI1NiIs..."
}

The account that creates the organization becomes its admin.

StatusCause
400A required field is missing
409{"detail": "this account already belongs to an organization"}
403The email domain is not permitted to create an organization on this deployment

nextneural_coach uses a different route and field​

POST /api/nn-coach/auth/organization

{ "organization_name": "Pragati AI" }

One field, named organization_name — not name — and no company metadata at all.

Read and update​

GET /api/organization — any member

{
"id": 1,
"name": "Pragati AI",
"website": "https://pragati.example",
"employee_count": "11-50",
"company_type": "generic_sales",
"waitlist_status": "approved"
}

PATCH /api/organization — admin only. Same fields as creation.

Waitlist approval​

New organizations may be gated behind manual approval. At signup the email domain is checked against ALLOWED_EMAIL_DOMAINS:

Domain waswaitlist_statusEffect
On the allowlist, or no allowlist configuredallowedNever gated
Not on the allowlistpendingBlocked until approved
—approvedCleared by hand
—rejectedBlocked, permanently

Both pending and rejected are blocked. The distinction is for whoever is reviewing the list, not for the check itself.

Signup and organization creation always succeed regardless of status — what the gate blocks is everything afterwards:

{ "detail": "your organization is awaiting approval", "needs_waitlist_approval": true }
Approval is manual and has no API

Moving an organization from pending to approved is deliberately an out-of-band database operation, not an endpoint:

UPDATE organizations SET waitlist_status = 'approved' WHERE id = 1;

Approval is a property of the organization, not the individual member — what is being vetted is the company signing up, so one update clears every member at once. The status is re-read from the database on every request, so it takes effect on the caller's next request without them logging in again.

Members​

All member routes require the admin role and refuse API keys.

BinaryPath
nextneural_converse/api/organization/members, :uuid identifier
nextneural_intel, nextneural_assist/api/organization/members, :id identifier
nextneural_coachPOST /api/nn-coach/auth/users only — see below

List members​

GET /api/organization/members

Add a member​

POST /api/organization/members

{
"email": "[email protected]",
"first_name": "Arjun",
"last_name": "Rao",
"role": "member"
}

email and role are required; role must be one of admin, manager, member. The new member is issued a temporary password, emailed an invite, and flagged must_change_password until they set their own.

Change a member's role​

PATCH /api/organization/members/{id}

{ "role": "manager" }

Remove a member​

DELETE /api/organization/members/{id}

Resend an invite​

POST /api/organization/members/{id}/resend-invite

Fails if the deployment has no email provider configured — a failed invite is reported rather than silently dropped.

nextneural_coach: create a user directly​

POST /api/nn-coach/auth/users — admin only

{
"email": "[email protected]",
"password": "their-initial-password",
"first_name": "Arjun",
"last_name": "Rao",
"role": "member"
}

nextneural_coach has no invite flow — the password is set here and communicated by whatever means you choose. There is no list, update, or delete counterpart.

Superadmin​

A platform-level capability, not an org role. It is derived from the caller's own email domain via SUPERADMIN_EMAIL_DOMAINS / SUPERADMIN_EMAIL, so it cannot be granted through the API.

BinaryPrefix
nextneural_converse, nextneural_intel, nextneural_assist/api/superadmin
nextneural_coach/api/nn-coach/auth/superadmin

List every organization​

GET /api/superadmin/organizations

{
"organizations": [
{ "id": 1, "name": "Pragati AI", "member_count": 4, "created_at": "2026-09-18T18:07:18Z" }
]
}

Enter an organization​

POST /api/superadmin/organizations/{id}/enter

Issues a new session token scoped to that organization, so an operator can see the app exactly as its members do. Their own users row still has no organization — the org travels on the token.

{ "token": "eyJhbGciOiJIUzI1NiIs...", "user": { "...": "..." } }

Grant or revoke app access​

PATCH /api/superadmin/organizations/{id}/app-access

{ "is_active": true }

Entitles an organization to use this particular app. An organization with no row is treated as active; an explicitly inactive one is refused by requireAppAccess on every org-scoped route.