Script it. Extend it. Make it yours.
Every Solid Vibes design is readable code. Drive it from your own scripts with the REST API and the typed SDK, write your own parametric features in TypeScript, and add panels and commands to the editor with sandboxed plugins.
REST API + SDK
Read and change Things with versioned ops, build on the server, read mass properties, export STL / 3MF / STEP / DXF, run the agent.
Read moreCustom features
FeatureScript-style macros in TypeScript. Typed parameters become a dialog; the code runs in a sandbox, in the browser and on the server.
Read moreEditor plugins
Panels, ⌘K commands and bundled features in a locked-down frame. Plugins propose changes; people accept them.
Read moreQuickstart
- Create a key in Workspace → Developer (Maker plan and up). Pick only the scopes it needs. You see the key once.
- Call the API with it as a bearer token, from a script or a server — never from a web page.
- Read a doc, send ops with the version you read, retry on
409. Open editors show your change live.
curl https://app.solidvibes.ai/api/v1/things \
-H "Authorization: Bearer $SOLIDVIBES_API_KEY"import { SolidVibes } from "@sv/sdk";
const sv = new SolidVibes({ apiKey: process.env.SOLIDVIBES_API_KEY! });
const [box] = await sv.things.all({ q: "router mount" });
await sv.things.setParameter(box.id, "width", 80); // retries on version conflicts
const build = await sv.things.build(box.id); // step errors + mass properties
const stl = await sv.exports.create(box.id, { format: "stl" });
console.log(build.total.massG, "g →", stl.url);The full reference is the OpenAPI 3.1 document at /api/v1/openapi.json — import it into Postman, Insomnia or a code generator. The typed TypeScript client lives in packages/sdk.
| Endpoint | Scope |
|---|---|
GET /api/v1/meThe key's workspace, scopes and rate limit | any |
GET /api/v1/thingsList Things | things:read |
GET /api/v1/things/{thingId}Get a Thing | things:read |
GET /api/v1/things/{thingId}/docGet the ThingDoc | things:read |
PATCH /api/v1/things/{thingId}/docChange the doc with ops | things:write |
POST /api/v1/things/{thingId}/buildBuild the pieces | things:read |
GET /api/v1/things/{thingId}/mass-propertiesMass properties | things:read |
GET /api/v1/things/{thingId}/exportsList exports | exports |
POST /api/v1/things/{thingId}/exportsExport a file | exports |
POST /api/v1/things/{thingId}/agentRun the agent on a prompt | agent |
Scopes
- things:read
- List Things, read their docs, build them and read mass properties.
- things:write
- Change a Thing's doc with ops (with version checks), like an edit in the editor.
- exports
- Export STL, 3MF, STEP or DXF files and list past exports.
- agent
- Send prompts to the agent. Uses your workspace's AI credits.
PATCH /api/v1/things/{thingId}/doc
{
"expectedVersion": 12,
"ops": [
{ "op": "piece_recipe", "pieceId": "p1",
"ops": [{ "op": "set_parameter", "name": "width", "value": 80 }] }
],
"message": "Wider for the new router"
}
→ 200 { "docVersion": 13, "describe": ["Box: Set width = 80 mm"] }
→ 409 { "error": { "code": "version_conflict", "details": { "expected": 12, "current": 13 } } }Hear back when things change
Add an HTTPS endpoint in Workspace → Developer. Changes made through the API (doc updates, finished exports, agent proposals) are POSTed as JSON with an X-SolidVibes-Signature header. Verify it with the secret you saw once.
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(body: string, header: string, secret: string) {
const { t, v1 } = Object.fromEntries(header.split(",").map((kv) => kv.split("=")));
const mac = createHmac("sha256", secret).update(`${t}.${body}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
return fresh && timingSafeEqual(Buffer.from(mac), Buffer.from(v1));
}Your own smart features, in TypeScript
Declare typed parameters — number, length, angle, switch, choice, a picked face or edges — and a build() that adds recipe steps with the same calls as the script view. Insert it from ⌘K: the parameters are a dialog with a live preview, and the recipe shows one sentence.
- • Runs in QuickJS (WebAssembly) with a 1.5 s, 32 MB budget, no network, no clock — the same code builds in your browser and on our servers.
- • Versioned per workspace. Steps keep the version they were made with; the code travels with the recipe.
- • Publish one to the Marketplace as a Feature listing; others add it to their workspace in one click.
export default feature({
name: "Peg row",
summary: "{count} pegs, {spacing} mm apart",
params: {
count: number({ label: "Pegs", default: 4, min: 1, max: 20, integer: true }),
spacing: length({ label: "Spacing", default: 15 }),
on: face({ label: "On face", default: "top" }),
},
build(p) {
for (let i = 0; i < p.count; i++) {
cylinder("peg_" + i, { radius: 2, height: 6, position: [i * p.spacing, 0, 0] });
}
},
});Extend the editor, safely
A plugin is a manifest plus one HTML page. Solid Vibes loads it in a sandboxed frame with no network and talks to it over postMessage: window.solidVibes.call(method, params).
Permissions (granted at install)
- doc:read
- Its pieces, parameters and recipe steps, and what you have selected. Nothing leaves your browser: plugins have no network access.
- ops:propose
- Suggest edits that appear as a ghost preview. Nothing changes until you press Accept.
- commands
- Add its own commands to the command palette.
- panel
- Show its own panel in the right column of the editor.
- features
- Install the custom features it comes with into this workspace (they run in the feature sandbox).
Methods: doc.get, selection.get, ops.propose, proposal.cancel, commands.register, features.list, features.open, ui.notify. Events: init, command, selection, doc, proposal.
{
"manifestVersion": 1,
"id": "my-plugin",
"name": "My plugin",
"version": "1.0.0",
"description": "What it does, in one sentence.",
"author": "You",
"permissions": ["doc:read", "ops:propose", "panel"],
"entry": "index.html",
"panel": { "title": "My panel" }
}Built to be safe to open up
- API keys are stored as SHA-256 fingerprints, scoped, expiring, revocable, rate limited per minute and every call is logged.
- The API accepts bearer keys only — never cookies — so other sites can’t use your session (no CSRF).
- Webhook URLs must be public HTTPS; every delivery re-checks the address, pins it and never follows redirects.
- Custom features and plugins run in sandboxes with no network, no access to the page and hard resource limits.