Orgs
Create a new organisation. The caller becomes the owner.
Fails with 409 if the caller already has an active org membership. Fails with 409 if the slug is already taken. Fails with 422 if the slug format is invalid.
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
application/json- body
name*Name2 <= length <= 200slug*Slug3 <= length <= 64Successful Response
application/json- response
created_at*Created Atdate-timeis_activated?Is Activatedfalsename*Nameorg_id*Org Iduuidslug*Slugyour_role?string|nullcurl -X POST 'https://api.aisc.sa/v1/orgs' \ -H 'Content-Type: application/json' \ -d '{ "name": "string", "slug": "string"}'{ "created_at": "2019-08-24T14:15:22Z", "is_activated": false, "name": "string", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "slug": "string", "your_role": "string"}Accept an invitation as the authenticated user.
Single-use (pending->accepted under FOR UPDATE), expiry- and revoke-checked, email-match guarded (the accepting user's email must equal the invited email), and one-active-org enforced. Bumps role_version so the joiner's next token re-resolves org_id.
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
application/json- body
token*Token8 <= length <= 128Successful Response
application/json- response
email*Emailjoined_at*Joined Atdate-timeleft_at?|nullmember_id*Member Iduuidrole*Roleuser_id*User Iduuidcurl -X POST 'https://api.aisc.sa/v1/orgs/invitations/accept' \ -H 'Content-Type: application/json' \ -d '{ "token": "stringst"}'{ "email": "string", "joined_at": "2019-08-24T14:15:22Z", "left_at": "2019-08-24T14:15:22Z", "member_id": "435a4844-006a-4cfc-a644-e8eb2dd2ca43", "role": "string", "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5"}PUBLIC (no auth): minimal preview for the /join landing page.
Returns only {organisation_name, role, inviter, email_registered}. Any miss (bad/expired/revoked/used token) is a generic non-enumerable 404. Expired pending invites are lazily flipped to 'expired'.
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
token*TokenSuccessful Response
application/json- response
email_registered*Email Registeredinviter*Inviterorganisation_name*Organisation Namerole*Rolecurl -X GET 'https://api.aisc.sa/v1/orgs/invitations/preview?token=string'{ "email_registered": true, "inviter": "string", "organisation_name": "string", "role": "string"}Return the caller's active organisation. 404 if the user is solo.
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
Successful Response
application/json- response
created_at*Created Atdate-timeis_activated?Is Activatedfalsename*Nameorg_id*Org Iduuidslug*Slugyour_role?string|nullcurl -X GET 'https://api.aisc.sa/v1/orgs/me'{ "created_at": "2019-08-24T14:15:22Z", "is_activated": false, "name": "string", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "slug": "string", "your_role": "string"}List PENDING invitations for the caller's org (never the token/hash).
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
Successful Response
application/json- response
invitations*array<>curl -X GET 'https://api.aisc.sa/v1/orgs/me/invitations'{ "invitations": [ { "created_at": "2019-08-24T14:15:22Z", "email": "string", "expires_at": "2019-08-24T14:15:22Z", "invitation_id": "a6e6785a-3ea9-406c-b873-17eaf2ed5fc9", "role": "string", "status": "string" } ]}Create a single-use, short-lived invite for email (registered or not).
Returns the RAW token + link ONCE (only its hash is stored). Best-effort emails the link. 409 if a pending invite for this (org, email) already exists, or if the email is already an active member of this org.
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
application/json- body
email*Email3 <= length <= 320role?Role^(owner|admin|member|viewer)$"member"Successful Response
application/json- response
email*Emailexpires_at*Expires Atdate-timeinvitation_id*Invitation Iduuidinvite_url*Invite Urlrole*Roletoken*Tokencurl -X POST 'https://api.aisc.sa/v1/orgs/me/invitations' \ -H 'Content-Type: application/json' \ -d '{ "email": "string"}'{ "email": "string", "expires_at": "2019-08-24T14:15:22Z", "invitation_id": "a6e6785a-3ea9-406c-b873-17eaf2ed5fc9", "invite_url": "string", "role": "string", "token": "string"}Revoke a pending invitation (immediate kill-switch).
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
invitation_id*Invitation IduuidSuccessful Response
curl -X DELETE 'https://api.aisc.sa/v1/orgs/me/invitations/497f6eca-6276-4993-bfeb-53cbbbba6f08'Return paginated active member list for the caller's org.
Keyset cursor is "<joined_at_iso>:<member_id>"; pass in ?after=<cursor>.
Members who have left (left_at IS NOT NULL) are excluded.
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
limit?Limit50after?string|nullSuccessful Response
application/json- response
members*array<>next_cursor?string|nullcurl -X GET 'https://api.aisc.sa/v1/orgs/me/members'{ "members": [ { "email": "string", "joined_at": "2019-08-24T14:15:22Z", "left_at": "2019-08-24T14:15:22Z", "member_id": "435a4844-006a-4cfc-a644-e8eb2dd2ca43", "role": "string", "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5" } ], "next_cursor": "string"}Invite an existing user (by email) to the caller's org.
The target user must already be registered.
The target user must not already have an active org membership.
Returns 201 {"member_id": "<uuid>"} on success.
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
application/json- body
email*Email3 <= length <= 320role?Role^(owner|admin|member|viewer)$"member"Successful Response
application/json- response
[key: string]?anycurl -X POST 'https://api.aisc.sa/v1/orgs/me/members' \ -H 'Content-Type: application/json' \ -d '{ "email": "string"}'{}Change a member's role.
Last-owner protection: if the target member is the last owner AND the new role is not 'owner', returns 409 ORG_LAST_OWNER.
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
member_id*Member Iduuidapplication/json- body
role*Role^(owner|admin|member|viewer)$Successful Response
application/json- response
email*Emailjoined_at*Joined Atdate-timeleft_at?|nullmember_id*Member Iduuidrole*Roleuser_id*User Iduuidcurl -X PATCH 'https://api.aisc.sa/v1/orgs/me/members/497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Content-Type: application/json' \ -d '{ "role": "string"}'{ "email": "string", "joined_at": "2019-08-24T14:15:22Z", "left_at": "2019-08-24T14:15:22Z", "member_id": "435a4844-006a-4cfc-a644-e8eb2dd2ca43", "role": "string", "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5"}Soft-remove a member (sets left_at = now()).
Last-owner protection: if the target is the last owner, returns 409. The removed user reverts to solo-tenant on their next request (role_version bump forces re-login, which re-resolves org_id = None).
BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
member_id*Member IduuidSuccessful Response
curl -X DELETE 'https://api.aisc.sa/v1/orgs/me/members/497f6eca-6276-4993-bfeb-53cbbbba6f08'BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
Successful Response
application/json- response
ai_training*can_change*Can Changellm_assistant*curl -X GET 'https://api.aisc.sa/v1/orgs/me/permissions'{ "ai_training": { "changed_at": "2019-08-24T14:15:22Z", "granted": true, "policy_version": "string" }, "can_change": true, "llm_assistant": { "changed_at": "2019-08-24T14:15:22Z", "granted": true, "policy_version": "string" }}BearerAuthAuthorizationBearer <token>JWT access token. Obtain via POST /v1/auth/login.
application/json- body
granted*Grantedlocale*Locale"ar""en"policy_version*Policy Version^[A-Za-z0-9.+:_-]+$1 <= length <= 80purpose*Purpose"ai_training""llm_assistant"source*Source"settings""signup"Successful Response
application/json- response
changed_at?|nullgranted*Grantedpolicy_version?string|nullcurl -X PUT 'https://api.aisc.sa/v1/orgs/me/permissions' \ -H 'Content-Type: application/json' \ -d '{ "granted": true, "locale": "ar", "policy_version": "string", "purpose": "ai_training", "source": "settings"}'{ "changed_at": "2019-08-24T14:15:22Z", "granted": true, "policy_version": "string"}