Notebook Sharing¶
The sharing system allows admins to create invite links for notebooks. Users who redeem an invite receive chat_only access to the notebook. Admins can manage invites and revoke access.
Base paths: /api/notebooks/{notebook_id} and /api/invite
POST /api/notebooks/{notebook_id}/invites¶
Create a new invite link for a notebook. The invite code is auto-generated and returned in the response.
Auth: Admin
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <token> |
Content-Type | application/json |
Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
expires_at | string (ISO 8601) | No | null | Expiration date (null = never expires) |
Status: 201 Created
| Code | Cause |
|---|---|
401 | Invalid or missing token |
403 | Non-admin user |
import httpx
notebook_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
response = httpx.post(
f"http://localhost:8000/api/notebooks/{notebook_id}/invites",
headers={"Authorization": f"Bearer {token}"},
json={"expires_at": "2026-03-25T00:00:00Z"},
)
invite = response.json()["data"]
print(f"Invite URL: {invite['invite_url']}")
GET /api/notebooks/{notebook_id}/invites¶
List all invites for a notebook.
Auth: Admin
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <token> |
Status: 200 OK
| Code | Cause |
|---|---|
401 | Invalid or missing token |
403 | Non-admin user |
import httpx
notebook_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
response = httpx.get(
f"http://localhost:8000/api/notebooks/{notebook_id}/invites",
headers={"Authorization": f"Bearer {token}"},
)
invites = response.json()["data"]
for inv in invites:
print(f" {inv['invite_code']}: redeemed {inv.get('redeemed_count', 0)} times")
DELETE /api/notebooks/{notebook_id}/invites/{invite_code}¶
Revoke an invite link. Existing access granted by this invite is NOT affected.
Auth: Admin
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <token> |
| Code | Cause |
|---|---|
401 | Invalid or missing token |
403 | Non-admin user |
404 | Invite not found |
GET /api/notebooks/{notebook_id}/access¶
List all users with access to a notebook (both admins and invited users).
Auth: Admin
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <token> |
Status: 200 OK
| Code | Cause |
|---|---|
401 | Invalid or missing token |
403 | Non-admin user |
DELETE /api/notebooks/{notebook_id}/access/{user_id}¶
Revoke a user's access to a notebook.
Auth: Admin
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <token> |
| Code | Cause |
|---|---|
401 | Invalid or missing token |
403 | Non-admin user |
404 | Access record not found |
POST /api/invite/{invite_code}/redeem¶
Redeem an invite code. Grants chat_only access to the associated notebook. The system searches across all configured databases (cloud and local) to find the invite.
Auth: User
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <token> |
Status: 200 OK
| Code | Cause |
|---|---|
401 | Invalid or missing token |
404 | Invite not found or already revoked |
410 | Invite has expired |
GET /api/invite/{invite_code}¶
Get public information about an invite link. Used by the frontend to display invite details before the user redeems it.
Auth: User
Headers:
| Header | Value |
|---|---|
Authorization | Bearer <token> |
Status: 200 OK
{
"success": true,
"data": {
"notebook_title": "Customer Support KB",
"notebook_icon": "\ud83d\udcca",
"is_valid": true,
"reason": null
}
}
When the invite is invalid:
{
"success": true,
"data": {
"notebook_title": "",
"notebook_icon": null,
"is_valid": false,
"reason": "not_found"
}
}
| Reason | Description |
|---|---|
null | Invite is valid |
"not_found" | Invite does not exist |
"expired" | Invite has expired |
"revoked" | Invite was revoked by admin |
| Code | Cause |
|---|---|
401 | Invalid or missing token |
import httpx
invite_code = "abc123def456"
response = httpx.get(
f"http://localhost:8000/api/invite/{invite_code}",
headers={"Authorization": f"Bearer {token}"},
)
info = response.json()["data"]
if info["is_valid"]:
print(f"Invite for: {info['notebook_title']}")
else:
print(f"Invalid: {info['reason']}")