Stashr docs
Projects
Projects are required. Every upload must belong to one project.
Use projects to separate assets by site, client, campaign, brand, product, or environment.
Slugs
Each project has a slug, such as website or launch-site. Slugs are used in API uploads and human-readable asset paths.
The workspace slug is chosen once during workspace setup. It is locked after setup because it is the first segment of public asset URLs.
If your workspace slug is acme, your project slug is website, and the folder is brand/launch, the public path reads like:
/acme/website/brand/launch/hero.webp
Limits
| Plan | Projects |
|---|---|
| Free | 1 |
| Hobby | 5 |
| Pro | Unlimited |
Every new account starts with a default project.
Create Projects
Create projects from the dashboard or with POST /api/v1/projects. Slugs are normalized to lowercase URL-safe text and must be unique inside your workspace.
const baseUrl = "https://stashr.dev";
const apiKey = process.env.STASHR_API_KEY;
const projectId = process.env.STASHR_PROJECT_ID || "";
const folderId = process.env.STASHR_FOLDER_ID || "";
const assetId = process.env.STASHR_ASSET_ID || "";
const authHeaders = { Authorization: "Bearer " + apiKey };const payload = {
"name": "Website",
"slug": "website",
"description": "Website assets"
};
const response = await fetch(baseUrl + "/api/v1/projects", {
method: "POST",
headers: { ...authHeaders, "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());Use GET /api/v1/projects to discover project IDs and current counts. PATCH /api/v1/projects/{projectId} can update the name or description. Slugs cannot be changed because they form part of public asset URLs.
No Root Uploads
Stashr does not allow workspace-root uploads. This keeps every asset tied to a project from the start.
Delete Projects
Deleting a project removes:
- its folders
- its assets
- stored files below that project
- delivery URLs and public paths for those assets
Deletion is permanent. The dashboard warns you first and requires typing the project slug before anything is deleted.
API deletion has the same confirmation:
const payload = {
"confirmSlug": "website"
};
const response = await fetch(baseUrl + "/api/v1/projects/" + projectId, {
method: "DELETE",
headers: { ...authHeaders, "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(await response.text());