Organizations
Organizations are the top-level container for all resources. All endpoints in this section use Supabase JWT authentication, not API keys.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /v1/organizations | Create an organization |
| GET | /v1/organizations/{org_id} | Get an organization |
| DELETE | /v1/organizations/{org_id} | Delete an organization |
| GET | /v1/organizations/{org_id}/members | List members |
| DELETE | /v1/organizations/{org_id}/members/{user_id} | Remove a member |
| POST | /v1/organizations/{org_id}/leave | Leave an organization |
| POST | /v1/organizations/{org_id}/transfer-ownership | Transfer ownership |
| POST | /v1/organizations/{org_id}/invitations | Create an invitation |
| GET | /v1/organizations/{org_id}/invitations | List pending invitations |
| POST | /v1/organizations/invitations/{token}/accept | Accept an invitation |
Create an Organization
POST /v1/organizations
Creates an organization, sets the caller as owner, creates a prod environment, and generates the first API key.
Auth: Supabase JWT
curl -X POST https://api.embedd.to/v1/organizations \
-H "Authorization: Bearer YOUR_SUPABASE_JWT" \
-H "Content-Type: application/json" \
-d '{"name": "my-company"}'
| Field | Required | Type | Description |
|---|---|---|---|
name | Yes | string | Unique organization name (1-100 chars) |
Response (201):
{
"organization": {
"id": "org_abc123",
"name": "my-company",
"status": "active",
"tier": "free",
"created_at": "2026-03-13T10:00:00Z"
},
"api_key": "sk_live_abc123..."
}
The api_key is the raw key, shown once. Store it immediately.
Errors:
| Status | Reason |
|---|---|
409 | Organization name already taken |
Get an Organization
GET /v1/organizations/{org_id}
Auth: Supabase JWT (requires membership)
curl https://api.embedd.to/v1/organizations/org_abc123 \
-H "Authorization: Bearer YOUR_SUPABASE_JWT"
Response (200):
{
"id": "org_abc123",
"name": "my-company",
"status": "active",
"tier": "free",
"created_at": "2026-03-13T10:00:00Z"
}
Delete an Organization
DELETE /v1/organizations/{org_id}
Marks the organization as deleting and enqueues an async cleanup task. The task deletes external resources (Qdrant collections, platform tables), then database records, then the organization itself.
Auth: Supabase JWT (owner only)
curl -X DELETE https://api.embedd.to/v1/organizations/org_abc123 \
-H "Authorization: Bearer YOUR_SUPABASE_JWT"
Response: 202 Accepted
Errors:
| Status | Reason |
|---|---|
403 | Not the owner |
409 | Organization is already being deleted |
List Members
GET /v1/organizations/{org_id}/members
Auth: Supabase JWT (any member)
curl https://api.embedd.to/v1/organizations/org_abc123/members \
-H "Authorization: Bearer YOUR_SUPABASE_JWT"
Response (200):
{
"data": [
{
"id": "mem_abc123",
"user_id": "usr_abc123",
"org_id": "org_abc123",
"role": "owner",
"user_email": "owner@company.com",
"user_name": "Jane Smith",
"created_at": "2026-03-13T10:00:00Z"
}
]
}
Remove a Member
DELETE /v1/organizations/{org_id}/members/{user_id}
Removes a member and revokes their API keys for the organization.
Auth: Supabase JWT (admin or owner)
curl -X DELETE https://api.embedd.to/v1/organizations/org_abc123/members/usr_xyz789 \
-H "Authorization: Bearer YOUR_SUPABASE_JWT"
Response: 204 No Content
Errors:
| Status | Reason |
|---|---|
403 | Insufficient role, or attempting to remove the owner |
404 | Member not found |
Leave an Organization
POST /v1/organizations/{org_id}/leave
Removes the caller's membership and revokes their API keys.
Auth: Supabase JWT (any member except owner)
curl -X POST https://api.embedd.to/v1/organizations/org_abc123/leave \
-H "Authorization: Bearer YOUR_SUPABASE_JWT"
Response: 204 No Content
Errors:
| Status | Reason |
|---|---|
403 | Owners cannot leave — transfer ownership or delete the org |
Transfer Ownership
POST /v1/organizations/{org_id}/transfer-ownership
Transfers the owner role to another member. The current owner becomes an admin.
Auth: Supabase JWT (owner only)
curl -X POST https://api.embedd.to/v1/organizations/org_abc123/transfer-ownership \
-H "Authorization: Bearer YOUR_SUPABASE_JWT" \
-H "Content-Type: application/json" \
-d '{"user_id": "usr_xyz789"}'
| Field | Required | Type | Description |
|---|---|---|---|
user_id | Yes | string | Target user (must be an existing member) |
Response (200):
{
"id": "mem_xyz789",
"user_id": "usr_xyz789",
"org_id": "org_abc123",
"role": "owner",
"user_email": "newowner@company.com",
"user_name": "John Doe",
"created_at": "2026-03-13T10:00:00Z"
}
Errors:
| Status | Reason |
|---|---|
403 | Not the owner |
404 | Target user is not a member of the org |
Create an Invitation
POST /v1/organizations/{org_id}/invitations
Invites a user to the organization by email. Invitations expire after 7 days.
Auth: Supabase JWT (admin or owner)
curl -X POST https://api.embedd.to/v1/organizations/org_abc123/invitations \
-H "Authorization: Bearer YOUR_SUPABASE_JWT" \
-H "Content-Type: application/json" \
-d '{"email": "teammate@company.com", "role": "admin"}'
| Field | Required | Type | Description |
|---|---|---|---|
email | Yes | string | Invitee's email address |
role | Yes | string | admin or member (not owner) |
Response (201):
{
"id": "inv_abc123",
"org_id": "org_abc123",
"email": "teammate@company.com",
"role": "admin",
"invited_by": "usr_abc123",
"expires_at": "2026-03-20T10:00:00Z",
"accepted_at": null,
"created_at": "2026-03-13T10:00:00Z"
}
Errors:
| Status | Reason |
|---|---|
403 | Insufficient role |
409 | User is already a member, or a pending invitation already exists |
List Pending Invitations
GET /v1/organizations/{org_id}/invitations
Returns invitations that have not been accepted.
Auth: Supabase JWT (admin or owner)
curl https://api.embedd.to/v1/organizations/org_abc123/invitations \
-H "Authorization: Bearer YOUR_SUPABASE_JWT"
Response (200):
{
"data": [
{
"id": "inv_abc123",
"org_id": "org_abc123",
"email": "teammate@company.com",
"role": "admin",
"invited_by": "usr_abc123",
"expires_at": "2026-03-20T10:00:00Z",
"accepted_at": null,
"created_at": "2026-03-13T10:00:00Z"
}
]
}
Accept an Invitation
POST /v1/organizations/invitations/{token}/accept
Accepts an invitation and creates a membership for the caller.
Auth: Supabase JWT
curl -X POST https://api.embedd.to/v1/organizations/invitations/inv_token_here/accept \
-H "Authorization: Bearer YOUR_SUPABASE_JWT"
Response (201):
{
"id": "mem_xyz789",
"user_id": "usr_xyz789",
"org_id": "org_abc123",
"role": "admin",
"user_email": "teammate@company.com",
"user_name": "John Doe",
"created_at": "2026-03-13T10:01:00Z"
}
Errors:
| Status | Reason |
|---|---|
404 | Invalid token |
410 | Invitation expired |
409 | Already a member of this organization |