Files, projects and knowledge
Upload files, organise work in projects, build and share knowledge bases, and manage teams through the REST API.
These are the resources that give a model something to work with. Files are uploads you attach to a message or run. Projects group chats, prompts and files with shared instructions and a default model. Knowledge bases are folder trees of documents that are indexed for retrieval and cited in answers. Teams are groups inside your workspace that you share projects, knowledge bases and conversations with.
All paths are relative to https://api.stickyprompts.com/api/v1. Every request runs as the user who owns the API key, so every ownership, sharing and workspace-role check applies to that user.
Conventions
- Objects carry capitalised base fields
ID,CreatedAt,UpdatedAtandDeletedAt(nullon live records) next to snake_case fields. - Paginated endpoints read
page(default1) andsize(default10) and set theX-Total-Count,X-PageandX-Page-Sizeresponse headers. See Errors, pagination and quotas. - Errors are
{"error": "message"}. Quota errors are429 {"error": "Quota exceeded", "reason": "<reason>"}.
Files
The File object
Every upload endpoint returns the same File object.
{
"ID": 4812,
"CreatedAt": "2026-09-28T09:14:03.512Z",
"UpdatedAt": "2026-09-28T09:14:03.512Z",
"DeletedAt": null,
"name": "northwind-q3-report.pdf",
"path": "https://<storage-host>/<bucket>/231/k9Tq2vX8bLmN3pRs7wYz4cDf6gHj1kLm.pdf",
"preview_path": "",
"public_path": "",
"user_id": 231,
"workspace_id": 17,
"project_id": null,
"fileType": "file_search",
"partial": false
}
| Field | Type | Meaning |
|---|---|---|
ID | integer | The file ID you pass as an attachment in conversations and runs. |
name | string | Original filename. |
path | string | Direct URL of the stored object: <storage URI>/<bucket>/<user id>/<32 random chars><extension>. Whether it can be read without credentials depends on storage configuration outside the API. |
preview_path | string | Set only for .docx (converted to a PDF preview) and .jfif (re-served as .jpg). Otherwise empty. |
public_path | string | Public share slug, empty when not shared. See POST /file/:id/public. |
user_id, workspace_id, project_id | integer or null | Uploader, their workspace at upload time, and the project if uploaded to one. |
fileType | string | camelCase key. image, file_search, spreadsheet, code_interpreter or code_interpreter_output, derived from the extension. |
partial | boolean | true only while generated content is still being written. Always false for uploads. |
How fileType is derived. The extension match is case-sensitive, so REPORT.PDF falls through to code_interpreter.
image:.png .jpg .jpeg .gif .webp .bmp .tiff .tif .ico .heic .heif .jfif .avif .svgfile_search:.c .cc .cpp .h .hpp .cs .css .scss .less .doc .docx .go .html .java .js .jsx .ts .tsx .vue .json .md .pdf .php .pptx .py .rb .sh .bat .ps1 .tex .txt .xml .yaml .yml .toml .ini .log .rtf .odt .rst .sql .kt .swift .rs .r .m .lua .plspreadsheet:.xlsx .xlsm .xlam .xltm .xltx .xls .csv .tsv .ods .ots .numberscode_interpreter: anything else
POST /file
/api/v1/file Uploads one or more files to your personal file library. The upload is synchronous: when the response arrives, each file is stored and has an ID. There is no MCP equivalent for uploading.
-
upload[]file form required - One part per file; repeat the field to upload several. The name is literally
upload[]: parts under any other name are ignored and the request succeeds with[].
The API code enforces no file size limit and no extension allow-list here; any limit you hit comes from infrastructure in front of the API.
curl -X POST https://api.stickyprompts.com/api/v1/file \
-H "Authorization: Bearer $STICKY_API_KEY" \
-F "upload[]=@northwind-q3-report.pdf" \
-F "upload[]=@pricing.xlsx"import os, requests
with open("northwind-q3-report.pdf", "rb") as a, open("pricing.xlsx", "rb") as b:
r = requests.post(
"https://api.stickyprompts.com/api/v1/file",
headers={"Authorization": f"Bearer {os.environ['STICKY_API_KEY']}"},
files=[("upload[]", a), ("upload[]", b)],
)
r.raise_for_status()
for f in r.json():
print(f["ID"], f["name"], f["fileType"])import { readFile } from "node:fs/promises";
const form = new FormData();
form.append("upload[]", new Blob([await readFile("northwind-q3-report.pdf")]), "northwind-q3-report.pdf");
form.append("upload[]", new Blob([await readFile("pricing.xlsx")]), "pricing.xlsx");
const files = await fetch("https://api.stickyprompts.com/api/v1/file", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.STICKY_API_KEY}` },
body: form,
}).then((r) => r.json());
console.log(files.map((f) => [f.ID, f.fileType]));Response. 200 with an array of File objects, in upload order.
Errors. 500 {"error": "could not upload files"} when the body is not valid multipart or storage fails.
Using an uploaded file
- In a conversation message or run:
"attachments": [{"id": 4812, "type": "file"}]. Add"temp": trueto attach it for that call only. See Conversations. - On a prompt:
POST /prompt/:id/filewith{"file_ids": [4812]}. See Prompts and runs. - For spreadsheet processing: pass it as
file_idtoPOST /xlsx/start-process. See Models and media.
GET /file
/api/v1/file Lists every file you uploaded, including files uploaded to projects and knowledge bases and generated spreadsheet outputs. No explicit sort order.
-
pageinteger query optional default1 - Page number.
-
sizeinteger query optional default10 - Items per page.
Response. 200 with an array of File objects.
DELETE /file/:id
/api/v1/file/:id Deletes a file you uploaded: removes it (and any preview) from storage and soft-deletes the record.
-
idinteger path required - File ID.
Response. 204, no body.
Errors. 400 {"error": "Invalid file ID"}, 404 {"error": "File not found"}, 403 {"error": "You do not have permission to delete this file"} (you are not the uploader), 502 {"error": "Failed to delete file"}.
POST /file/:id/public
/api/v1/file/:id/public Creates or replaces a public share slug for a file you uploaded. Calling it again generates a new slug and invalidates the old one. Anyone holding the slug can call GET /public/file/:slug without authentication; it returns the File object, including path (and 404 {"error": "File not found"} once revoked). The API does not define a share URL format on top of the slug.
-
idinteger path required - File ID.
Response. 200 with the File object, public_path set to a new 32-character slug such as "Qx7_mB2kLr9-TtZwP4nV8cHd3JfG6sYq".
Errors. 400 Invalid file ID, 404 File not found, 403 {"error": "You do not have permission to share this file"}.
DELETE /file/:id/public
/api/v1/file/:id/public Revokes the public link by clearing public_path.
-
idinteger path required - File ID.
Response. 204. Errors. 400 Invalid file ID, 404 File not found, 403 {"error": "You do not have permission to modify this file"}.
Projects
A project groups conversations, prompts and files, and carries default instructions and a default model: the API side of Projects. Every :id accepts the numeric ID or the slug. Files uploaded to a project are automatically attached, for that call only, to conversations started in the project (use the X-Project-ID header on the conversation endpoints).
Access model
- The owner can do everything. Only the owner can delete the project or change its sharing.
- Others get access through shares to the whole workspace, individual users or teams; the effective flags are the union. Being shared grants view access (see the project and its files, pin it). Extra flags:
prompt_management(manage its prompts),file_management(upload and delete files) andproject_management(edit it withPATCH).
The Project object
{
"ID": 305,
"CreatedAt": "2026-09-01T12:00:00Z",
"UpdatedAt": "2026-09-27T16:40:00Z",
"DeletedAt": null,
"slug": "k7Tq2vX",
"name": "Northwind Launch",
"description": "Everything for the Q4 launch",
"instructions": "Answer in British English. Keep it short.",
"color": "#3B82F6",
"icon": "rocket",
"ai_model_id": null,
"auto_model_type": "best",
"user_id": 231,
"is_pinned": false,
"has_files": true,
"current_user_permission": { "prompt_management": false, "file_management": false, "project_management": false },
"workspace_share": true,
"workspace_share_flags": { "prompt_management": true, "file_management": false, "project_management": false },
"user_shares": [
{ "user_id": 240, "user": { "ID": 240, "first_name": "Dora", "...": "..." },
"flags": { "prompt_management": true, "file_management": true, "project_management": false } }
],
"team_shares": [
{ "team_id": 12, "team": { "ID": 12, "name": "Marketing", "...": "..." },
"flags": { "prompt_management": false, "file_management": true, "project_management": false } }
]
}
iconmust be empty or one offolder rocket hat-glasses box flask-conical book-open briefcase circle-dollar-sign puzzle cpu plane cross database paw-print headset.coloris a hex string and is not validated.- Normally exactly one of
ai_model_id(a fixed model) orauto_model_type(best,balanced,fastest) is set. ai_model,pin,files,conversations,promptsandhas_filesare omitted when not loaded.current_user_permissionreflects only flags granted through shares; the owner has full rights but usually sees allfalse.has_files,current_user_permission,user_sharesandteam_sharesare filled only byGET /project/:id. Elsewherehas_filesis omitted, the permission flags are allfalseand the share lists arenull.
POST /project
/api/v1/project Creates a project. The default model comes from your preferences (preferred model or auto mode), falling back to the platform default. instructions cannot be set here: use PATCH.
-
namestring required - Project name.
-
descriptionstring optional - Free text.
-
colorstring optional - Hex color.
-
iconstring optional - One of the icon names above.
curl -X POST https://api.stickyprompts.com/api/v1/project \
-H "Authorization: Bearer $STICKY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Northwind Launch", "description": "Everything for the Q4 launch", "icon": "rocket" }'
Response. 201 with the Project object.
Errors. 400 ("Project name is required" or a binding error, "Invalid project icon"), 500 {"error": "Failed to create project"}.
GET /project
/api/v1/project Lists projects you own plus projects shared with you, newest first.
-
pageinteger query optional default1 - Page number.
-
sizeinteger query optional default10 - Items per page.
-
searchstring query optional - Case-insensitive match on name or description.
-
is_sharedboolean query optional true: only projects shared with you.false: only projects you own. Omit for both.
Response. 200 with an array of Project objects.
Access filtering is applied after pagination, so a page can hold fewer than size items and X-Total-Count can be higher than what you can see. is_pinned is always false in this list: use GET /project/pinned. Errors. 400 {"error": "Invalid is_shared parameter"}.
GET /project/pinned
/api/v1/project/pinned Your pinned projects, oldest pin first, with is_pinned: true and pin populated. Not paginated.
GET /project/:id
/api/v1/project/:id Returns the full Project object.
-
idstring path required - Project ID or slug.
-
include_filesstring query optional trueincludes the project’s files asfiles(File objects).
Errors. 404 {"error": "Project not found"}, 403 {"error": "You don't have access to this project"}.
PATCH /project/:id
/api/v1/project/:id Updates a project. You must be the owner or hold project_management. Every field is optional, but send at least one.
-
idstring path required - Project ID or slug.
-
namestring optional - Cannot be empty.
-
descriptionstring optional - Free text.
-
colorstring optional - Hex color.
-
iconstring optional - Icon name, or
""to clear. -
instructionsstring optional - Project-level instructions for the model. Your workspace’s sensitive-data rules apply: matching content is redacted or the request is rejected.
-
ai_model_idinteger optional - Sets a fixed model and clears
auto_model_type. -
auto_model_typestring optional best,balancedorfastest. Clearsai_model_id.
Response. 200 with the Project object.
Errors. 400 for Project name cannot be empty, only one of ai_model_id or auto_model_type may be set, invalid auto_model_type, Invalid project icon, No fields provided for update, or a sensitive-data block ({"error": "...", "code": "..."}); 404 Project not found; 403 You don't have access to this project.
DELETE /project/:id
/api/v1/project/:id Deletes the project together with its conversations, project files, pins, prompts and share records. Owner only.
-
idstring path required - Project ID or slug.
Response. 204. Errors. 404 Project not found, 403 You don't have access to this project.
POST /project/:id/pin
/api/v1/project/:id/pin Toggles your pin on a project you can view. At most 5 pinned projects per user.
-
idstring path required - Project ID or slug.
Response. 200 {"message": "Project pinned", "pinned": true} or 200 {"message": "Project unpinned", "pinned": false}.
Errors. 400 {"error": "Maximum 5 projects can be pinned"}, 404, 403.
PATCH /project/:id/share_with_workspace
/api/v1/project/:id/share_with_workspace Shares the project with your whole workspace, or removes that share. Owner only; you must belong to a workspace. Flags you omit keep their current value.
-
idstring path required - Project ID or slug.
-
shareboolean optional trueshares with the workspace,falseremoves the share. Omitted: nothing changes.-
prompt_managementboolean optional - Applied only together with
share: true. -
file_managementboolean optional - Applied only together with
share: true. -
project_managementboolean optional - Applied only together with
share: true.
Response. 200 {"message": "Project shared with workspace"}, also when unsharing.
Errors. 403 {"error": "You don't have access to this project's share settings"}, 400 {"error": "User is not in a workspace"}, 404.
PATCH /project/:id/share_with_user
/api/v1/project/:id/share_with_user Shares the project with individual users in your workspace. Owner only.
-
idstring path required - Project ID or slug.
-
sharesarray required - Entries
{ "user_id", "share", "prompt_management", "file_management", "project_management" }.share: truegrants view access;share: falseremoves the user’s share entirely; omittedshareonly patches the flags given.
{
"shares": [
{ "user_id": 240, "share": true, "prompt_management": true, "file_management": true },
{ "user_id": 251, "share": false }
]
}
Entries are applied in order and the request stops at the first failing entry; earlier entries stay applied.
Response. 200 {"message": "Project sharing with users updated"}.
Errors. 404 {"error": "User not found"}, 400 {"error": "Target user is not in the same workspace"}, plus the owner and workspace errors above.
PATCH /project/:id/share_with_team
/api/v1/project/:id/share_with_team The same as share_with_user, but entries use team_id. The team must belong to your workspace.
-
idstring path required - Project ID or slug.
-
sharesarray required - Entries
{ "team_id", "share", "prompt_management", "file_management", "project_management" }.
Response. 200 {"message": "Project sharing with teams updated"}.
Errors. 404 {"error": "Team not found"}, 400 {"error": "Target team is not in the same workspace"}.
POST /project/:id/file
/api/v1/project/:id/file Uploads files into a project. You must be the owner or hold file_management. Same mechanics as POST /file: synchronous, multipart/form-data, no size limit or extension allow-list in the API code. Each resulting File has project_id set.
-
idstring path required - Project ID or slug.
-
upload[]file form required - One part per file; repeat for several.
Response. 200 with an array of File objects.
Errors. 404 Project not found, 403 {"error": "You don't have access to this project"}, 500 {"error": "could not upload files"}.
GET /project/:id/file
/api/v1/project/:id/file Lists a project’s files. Each is a File object plus can_delete (true if you can manage project files or uploaded the file). preview_path falls back to path when there is no preview.
-
idstring path required - Project ID or slug.
[
{
"ID": 4820,
"name": "brand-guidelines.pdf",
"path": "https://<storage-host>/<bucket>/231/Hq3...pdf",
"preview_path": "https://<storage-host>/<bucket>/231/Hq3...pdf",
"project_id": 305,
"fileType": "file_search",
"partial": false,
"can_delete": true
}
]
DELETE /project/:id/file/:fileId
/api/v1/project/:id/file/:fileId Removes a file record from the project. You need view access, and either file_management (or ownership of the project) or to be the file’s uploader.
-
idstring path required - Project ID or slug.
-
fileIdinteger path required - File ID.
Response. 200 {"message": "File deleted successfully"}.
Errors. 400 Invalid file ID, 404 Project not found, 404 {"error": "File not found in project"}, 403 {"error": "You don't have access to delete this file"}.
Knowledge bases
A knowledge base is a folder tree of documents that are chunked and indexed for retrieval: the API side of Knowledge bases. Use one in a conversation or run by passing knowledge_base_ids, optionally with knowledge_base_limit_node_ids to restrict retrieval to specific folders or files, and world_knowledge. Knowledge base IDs are numeric only (no slugs).
Access levels (current_user_permission and share access_type):
| Value | Can do |
|---|---|
kb_access | Read the knowledge base and use it in chats. |
kb_upload | The above, plus upload files. |
kb_edit | The above, plus rename it, manage folders and delete any file. |
none | No access. |
The owner always has kb_edit. Only the owner can delete the knowledge base or change its sharing. Uploaders can always delete their own files.
The Knowledge base object
{
"ID": 44,
"CreatedAt": "2026-09-10T08:30:00Z",
"UpdatedAt": "2026-09-10T08:30:00Z",
"DeletedAt": null,
"user_id": 231,
"user": { "ID": 0, "email": "", "first_name": "", "...": "zero values" },
"name": "Northwind Help Center",
"description": "Policies, onboarding and FAQs",
"color": "#10B981",
"icon": "book-open",
"document_count": 18,
"member_count": 6,
"current_user_permission": "kb_edit",
"user_shares": [
{ "user_id": 240, "user": { "ID": 240, "first_name": "Dora", "...": "..." }, "access_type": "kb_upload", "added_at": "2026-09-11T09:00:00Z" }
],
"team_shares": [
{ "team_id": 12, "team": { "ID": 12, "name": "Customer Support", "...": "..." }, "access_type": "kb_access", "added_at": "2026-09-11T09:05:00Z" }
]
}
The owner object user is never loaded and always has zero values: use user_id. document_count counts files, not folders. member_count is returned only by GET and PUT on a single knowledge base.
POST /knowledge-bases
/api/v1/knowledge-bases Creates a knowledge base.
-
namestring required - Knowledge base name.
-
iconstring required - One of the icon names listed under Projects.
-
descriptionstring optional - Free text.
-
colorstring optional - Hex color (not validated).
Response. 201 with the knowledge base, document_count: 0, member_count: 0 and empty share lists.
Errors. 400 {"error": "Knowledge base name is required"}, 400 {"error": "Invalid knowledge base icon"}.
GET /knowledge-bases
/api/v1/knowledge-bases Lists every knowledge base you own or can access through a share. Not paginated. Each item has the knowledge base fields plus document_count and current_user_permission (no member_count or share lists).
GET /knowledge-bases/:id
/api/v1/knowledge-bases/:id Returns the full knowledge base. Requires at least kb_access.
-
idinteger path required - Knowledge base ID.
Errors. 400 Invalid knowledge base ID, 404 Knowledge base not found, 403 {"error": "You don't have access to this knowledge base"}.
PUT /knowledge-bases/:id
/api/v1/knowledge-bases/:id Replaces name, description, color and icon, with the same body and validation as POST. An omitted description is cleared. Requires kb_edit.
-
idinteger path required - Knowledge base ID.
-
namestring required - Knowledge base name.
-
iconstring required - Icon name.
-
descriptionstring optional - Cleared when omitted.
-
colorstring optional - Hex color.
Response. 200 with the full knowledge base.
Errors. As for POST, plus 403 {"error": "You are not authorized to update this knowledge base"} and 404.
DELETE /knowledge-bases/:id
/api/v1/knowledge-bases/:id Deletes the knowledge base with all its folders, files, stored objects and index data. Owner only.
-
idinteger path required - Knowledge base ID.
Response. 204. Errors. 404 Knowledge base not found, 403 {"error": "You are not authorized to delete this knowledge base"}.
PATCH /knowledge-bases/:id/share_with_user
/api/v1/knowledge-bases/:id/share_with_user Shares a knowledge base with users in your workspace. Owner only; you must be in a workspace. Removing a share triggers a re-check of agents that use this knowledge base.
-
idinteger path required - Knowledge base ID.
-
sharesarray required - Entries
{ "user_id", "access_type" }.access_typeiskb_access,kb_uploadorkb_editto set (replacing the previous level), ornull,""ornoneto remove the share.
{
"shares": [
{ "user_id": 240, "access_type": "kb_upload" },
{ "user_id": 251, "access_type": null }
]
}
Entries are applied in order and processing stops at the first failing entry.
Response. 200 {"message": "Knowledge base sharing with users updated"}.
Errors. 400 {"error": "User is not in a workspace"}, 403 {"error": "You don't have access to this knowledge base's share settings"}, 404 User not found, 400 Target user is not in the same workspace, 400 {"error": "Invalid access_type"}.
PATCH /knowledge-bases/:id/share_with_team
/api/v1/knowledge-bases/:id/share_with_team The same as share_with_user, with team_id instead of user_id.
-
idinteger path required - Knowledge base ID.
-
sharesarray required - Entries
{ "team_id", "access_type" }.
Response. 200 {"message": "Knowledge base sharing with teams updated"}.
GET /knowledge-bases/:id/folders
/api/v1/knowledge-bases/:id/folders Lists the direct children, folders and files, of one level of the tree. This is also the endpoint to poll for a file’s indexing status.
-
idinteger path required - Knowledge base ID.
-
parent_idinteger query optional - Folder node ID to list. Omit (or pass a non-numeric value) for the root.
{
"folders": [
{ "ID": 501, "name": "Policies", "parent_id": null, "size": 2483112,
"CreatedAt": "2026-09-10T08:31:00Z", "UpdatedAt": "2026-09-10T08:31:00Z" }
],
"files": [
{
"ID": 502,
"name": "Northwind Refund Policy.md",
"parent_id": null,
"file_data_id": 4830,
"file_data": { "ID": 4830, "name": "Northwind Refund Policy.md", "fileType": "file_search", "...": "..." },
"size": 912334,
"download_url": "https://<storage-host>/<bucket>/231/Zp8...md",
"preview_url": "https://<storage-host>/<bucket>/231/Zp8...md",
"status": "done",
"status_progress": 100,
"can_delete": true,
"CreatedAt": "2026-09-10T08:32:00Z",
"UpdatedAt": "2026-09-10T08:33:10Z"
}
]
}
POST /knowledge-bases/:id/folders
/api/v1/knowledge-bases/:id/folders Creates a folder. Requires kb_edit. Names must be unique among siblings; folders and files share the namespace.
-
idinteger path required - Knowledge base ID.
-
namestring required - Folder name.
-
parent_idinteger optional - A folder in the same knowledge base. Omit or
nullfor the root.
Response. 201. The current implementation returns the folder with zero values ("ID": 0, empty name) even though it was created: re-list with GET /knowledge-bases/:id/folders to get the new folder’s ID.
Errors. 403 {"error": "You don't have access to create folders in this knowledge base"}, 400 {"error": "Folder name is required"}, 404 {"error": "Parent folder not found"}, 400 {"error": "Folder or document with this name already exists"}.
GET /knowledge-bases/:id/folders/:folderId
/api/v1/knowledge-bases/:id/folders/:folderId Returns one folder: ID, name, parent_id, size, CreatedAt, UpdatedAt. Requires kb_access.
-
idinteger path required - Knowledge base ID.
-
folderIdinteger path required - Folder node ID.
Errors. 404 {"error": "Folder not found"}, 403.
PATCH /knowledge-bases/:id/folders/:folderId
/api/v1/knowledge-bases/:id/folders/:folderId Renames a folder. Folders cannot be moved. Requires kb_edit.
-
idinteger path required - Knowledge base ID.
-
folderIdinteger path required - Folder node ID.
-
namestring required - New name. A blank name gives
400 {"error": "No fields provided for update"}.
Response. 200 with the updated folder. Errors. 400 {"error": "Folder or document with this name already exists"}.
DELETE /knowledge-bases/:id/folders/:folderId
/api/v1/knowledge-bases/:id/folders/:folderId Deletes the folder and everything under it, including stored files and index data. Requires kb_edit.
-
idinteger path required - Knowledge base ID.
-
folderIdinteger path required - Folder node ID.
Response. 204.
POST /knowledge-bases/:id/files
/api/v1/knowledge-bases/:id/files Uploads one document per request. Requires kb_upload or higher; quota is checked first. The file must have a unique name within the target folder. No file size limit is enforced in the API code.
-
idinteger path required - Knowledge base ID.
-
filefile form required - The document. The field name is
file, notupload[]. Allowed extensions (case-insensitive):.txt .md .markdown .pdf .docx .xlsx .csv .png .jpg .jpeg. -
folder_idstring form optional - Target folder node ID. Omit for the root.
curl -X POST https://api.stickyprompts.com/api/v1/knowledge-bases/44/files \
-H "Authorization: Bearer $STICKY_API_KEY" \
-F "file=@Northwind Refund Policy.md" \
-F "folder_id=501"import os, time, requests
BASE = "https://api.stickyprompts.com/api/v1"
H = {"Authorization": f"Bearer {os.environ['STICKY_API_KEY']}"}
with open("Northwind Refund Policy.md", "rb") as f:
node = requests.post(f"{BASE}/knowledge-bases/44/files", headers=H,
files={"file": f}, data={"folder_id": "501"}).json()
# Wait until the document is indexed before relying on it
while True:
listing = requests.get(f"{BASE}/knowledge-bases/44/folders", headers=H,
params={"parent_id": 501}).json()
status = next(x["status"] for x in listing["files"] if x["ID"] == node["ID"])
if status in ("done", "error"):
print(status)
break
time.sleep(3)import { readFile } from "node:fs/promises";
const BASE = "https://api.stickyprompts.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.STICKY_API_KEY}` };
const form = new FormData();
form.append("file", new Blob([await readFile("Northwind Refund Policy.md")]), "Northwind Refund Policy.md");
form.append("folder_id", "501");
const node = await fetch(`${BASE}/knowledge-bases/44/files`, { method: "POST", headers, body: form }).then((r) => r.json());
for (;;) {
const { files } = await fetch(`${BASE}/knowledge-bases/44/folders?parent_id=501`, { headers }).then((r) => r.json());
const { status } = files.find((x) => x.ID === node.ID);
if (status === "done" || status === "error") { console.log(status); break; }
await new Promise((r) => setTimeout(r, 3000));
}Response. 201 with a file node (the same shape as the files items above) in status: "uploading", status_progress: 0. Upload, text extraction and indexing then run in the background:
status | status_progress |
|---|---|
uploading | Upload percentage |
processing | 0 |
indexing | Indexing percentage |
done | 100 |
error | Processing failed |
Poll GET /knowledge-bases/:id/folders?parent_id=<folder_id> until the file is done before relying on it in retrieval.
Errors. 403 {"error": "You don't have access to upload files to this knowledge base"}, 429 quota exceeded, 400 {"error": "File is required"}, 400 {"error": "Invalid folder ID"}, 404 {"error": "Parent folder not found"}, 400 {"error": "File extension not allowed. Allowed extensions: .txt, .md, ..."}, 400 {"error": "Folder or document with this name already exists"}.
DELETE /knowledge-bases/:id/files/:fileId
/api/v1/knowledge-bases/:id/files/:fileId Deletes a document node, its stored file and its index data. Requires kb_edit, or being the file’s uploader.
-
idinteger path required - Knowledge base ID.
-
fileIdinteger path required - The node ID from the folder listing, not the File ID.
Response. 204. Errors. 404 {"error": "File not found"}, 403 {"error": "You don't have access to delete this file"}.
Teams
Teams live inside a workspace and are share targets for projects, knowledge bases and conversations. Team roles are owner and member; in workspace-wide listings, none means you are not in the team. See Users and teams for the admin view.
| Action | Allowed for |
|---|---|
| Create a team | Workspace owner or admin |
| List all teams in the workspace | Workspace owner or admin |
| See a team’s members | Team members, workspace owner or admin |
| Rename or delete a team, add or remove members | Team owner, workspace owner or admin |
Change a member’s role, add a member as owner, remove an owner | Workspace owner or admin |
The Team object
{
"ID": 12,
"CreatedAt": "2026-09-05T10:00:00Z",
"UpdatedAt": "2026-09-05T10:00:00Z",
"DeletedAt": null,
"workspace_id": 17,
"workspace": { "ID": 0, "name": "", "...": "zero values" },
"name": "Marketing",
"description": "Campaigns and content",
"color": "#F472B6",
"member_count": 0
}
workspace is never loaded and is always a zero-valued object. member_count is meaningful only in the list endpoints.
A team member is a User object (ID, email, first_name, last_name, status, workspace_id and more) with the member’s role added at the top level.
POST /teams
/api/v1/teams Creates a team and adds you as its owner. Workspace owner or admin only.
-
namestring required - Team name.
-
descriptionstring optional - Free text.
-
colorstring optional - Hex color (not validated).
Response. 201 with the Team object.
Errors. 403 {"error": "You are not authorized to create a team"}, 400 {"error": "Team name is required"}.
GET /teams
/api/v1/teams Teams you belong to, each with member_count and current_user_role. Not paginated. Returns null, not [], when you are in no team.
GET /teams/all
/api/v1/teams/all Every team in your workspace, with member_count and current_user_role (none if you are not a member). Workspace owner or admin only. Returns null when the workspace has no teams.
Errors. 404 {"error": "User is not a member of a workspace"}, 403 {"error": "You are not authorized to view all teams in this workspace"}.
GET /teams/:id/members
/api/v1/teams/:id/members Lists a team’s members. Team members and workspace owners or admins only.
-
idinteger path required - Team ID.
Response. 200 with an array of team members.
Errors. 400 Invalid team ID, 404 {"error": "Team not found"}, 403 {"error": "You are not authorized to view the members of this team"}.
PUT /teams/:id
/api/v1/teams/:id Replaces a team’s name, description and color; omitted description and color are cleared. Team owner or workspace owner or admin.
-
idinteger path required - Team ID.
-
namestring required - Team name.
-
descriptionstring optional - Cleared when omitted.
-
colorstring optional - Cleared when omitted.
Response. 200 with the updated Team.
Errors. 403 {"error": "You are not authorized to update this team"}, 400 Team name is required, 404 Team not found.
DELETE /teams/:id
/api/v1/teams/:id Deletes a team that has at most one member. Team owner or workspace owner or admin.
-
idinteger path required - Team ID.
Response. 204. Errors. 409 {"error": "Cannot delete a team with other members"}, 403 {"error": "You are not authorized to delete this team"}.
POST /teams/:id/members
/api/v1/teams/:id/members Adds a workspace member to a team. Team owner or workspace owner or admin; adding someone as owner needs workspace owner or admin.
-
idinteger path required - Team ID.
-
user_idinteger required - A user in your workspace.
-
rolestring required - Always send
memberorowner; the value is not validated beyond the owner check.
Response. 201. The body currently contains only role, with every user field at zero values: call GET /teams/:id/members to read the member back.
Errors. 403 {"error": "You are not authorized to add a team member"}, 403 when adding an owner without workspace admin rights, 409 {"error": "User is already a member of this team"}, 404 {"error": "User not found"}, 403 {"error": "User is not a member of this workspace"}.
PATCH /teams/:id/members/:memberUserId
/api/v1/teams/:id/members/:memberUserId Changes a member’s role. Changing role needs workspace owner or admin.
-
idinteger path required - Team ID.
-
memberUserIdinteger path required - The member’s user ID.
-
rolestring required ownerormember.
Response. 200 with the team member and the new role.
Errors. 404 {"error": "Team member not found"}, 403 {"error": "You are not authorized to update this team member"}, 403 {"error": "Updating the role of this team member requires workspace admin permissions"}.
DELETE /teams/:id/members/:memberUserId
/api/v1/teams/:id/members/:memberUserId Removes a member. Team owner or workspace owner or admin; removing an owner needs workspace owner or admin. You cannot remove yourself.
-
idinteger path required - Team ID.
-
memberUserIdinteger path required - The member’s user ID.
Response. 204.
Errors. 403 {"error": "You cannot remove yourself from a team"}, 403 {"error": "You are not authorized to remove this team member"}, 404 Team member not found, 403 {"error": "Removing an owner requires workspace admin permissions"}.
Related
- Conversations and messages - attach files and knowledge bases to a message.
- Models and media - spreadsheet processing over an uploaded file.
- MCP tool reference -
list_files,get_file, the project, knowledge base and team tools.