HTTP API
This service builds a VXL document into delivery files: STEP, STL, 3MF, renders and a verification
report. It runs on VextCAD's Linux build cell. You need no local VextCAD install: write a
*.vxl.json document (for example with the vextcad-vxl agent skill), send it, and download the
result.
- Base URL:
https://api.vextcad.com - Every route starts with
/api/v1/. - Requests and responses are JSON, except the archive download and asset uploads.
1. Quick start with the client
vextonline.mjs (in tools/client/ here, also bundled with the vextcad-vxl skill) needs only
Node.js 22+.
export VEXTONLINE_TOKEN='vxk1.<key_id>.<secret>' # or save it in ~/.config/vextonline/token (chmod 600)
node vextonline.mjs check part.vxl.json # static check, about 1 s
node vextonline.mjs build part.vxl.json --output-dir out # build, wait, download, extract
node vextonline.mjs build part.vxl.json --output-dir out \
--asset stock=stock.step --overrides '{"width": 40}' # with an input asset and overrides
out/ has the same layout as a local vextcad vxl build:
out/generations/<name>/terminals/<part>__body.{step,stl,3mf}
out/generations/<name>/renders/*.png
out/generations/<name>/manifest-v1.json
out/report/summary.json always for RELEASE and HOLD
out/report/revision-packet.json for HOLD and FAILED: what to fix
Client exit codes:
| Code | Meaning |
|---|---|
| 0 | RELEASE or HOLD (or check ok) |
| 3 | FAILED verdict or check not ok: read the report and fix the document |
| 2 | Request rejected |
| 1 | Service or network failure: retry later |
2. Results: RELEASE, HOLD, FAILED
A finished build has status: "completed" and a verdict:
| Verdict | Meaning |
|---|---|
RELEASE |
Every requirement in the document was measured and passed. |
HOLD |
Files are delivered, but something is open: an unanswered questions[] entry, a requirement that could not be measured, or a failed measurement. revision-packet.json says which. |
FAILED |
The document could not be built, for example a modelling step failed. Nothing is installed. The revision packet names the failing statement. |
The build cell is development_unqualified. RELEASE means "matches the document's own measured
requirements on this cell". It is not a print or engineering certification. Slicing and
printing (for example in Bambu Studio) are up to you.
status: "failed" means the service could not run the build, not that the design is wrong.
error.code is one of:
error.code |
Meaning |
|---|---|
infrastructure |
Service fault; retry |
timeout |
Exceeded timeout_ms |
invalid_input |
The document does not pass check; run check |
asset_missing |
A declared asset was not supplied |
expired |
Queued for over an hour |
3. Authentication
Send your key on every request:
Authorization: Bearer vxk1.<key_id>.<secret>
- Keys are issued by the operator, and the full key is shown only once. Keep it secret.
- A missing, wrong or revoked key gets
401 unauthorized. - Each key belongs to one tenant; you see only your own builds and uploads.
4. Endpoints
GET /api/v1/health
Returns 200 {"ok": true}. No authentication.
POST /api/v1/checks
{"document": { ...VXL... }, "overrides": {"param": 1}, "assets": {"stock": {"upload_key": "uploads/<tenant>/<uuid>"}}}
assets is required when the document declares assets, and has the same form as in a build.
Returns 200 {"ok": true|false, "report": {...}}.
ok: falsemeans the document has errors.report.messagenames the first error code, its JSON pointer and the valid values.- This is the same static check as
vextcad vxl check. It does not build.
POST /api/v1/uploads
Use this for asset files that the document declares in assets[]: STEP up to 32 MiB, STL up to
64 MiB, SVG (image/svg+xml) up to 2 MiB. Uploading needs an Ingot balance of at least 500.
{"id": "stock", "media_type": "model/step", "byte_length": 15385}
Returns 200 {"upload_key", "put_url", "put_headers", "expires_at"}.
PUTthe exact file bytes toput_url, withput_headers, within 15 minutes.- Pass
upload_keyto the build. - Uploads are deleted after 1 day.
POST /api/v1/inspections
Inspect one uploaded STEP (up to 32 MiB) before selecting faces for an imported part:
{"upload_key": "uploads/<tenant>/<uuid>", "import": {"source_units": "mm"}}
import and import.source_units are required. Units must be mm or inch; there is no
default. Optional import.heal is an object (default {"mode":"none"}), import.at is an
array (default [0,0,0] in mm), and import.rotate is an array (default []). The engine
validates their contents using the VXL import rules, including bounded/tolerant healing.
Use the same options as the VXL import step that will consume the asset. Returns 202 {"build_id", "status": "queued", "status_url"}. Poll the existing
GET /api/v1/builds/{build_id} until completed or failed. An inspection has kind: "inspect"
and no build verdict; a completed result adds inspection (the full
vextcad.vxl_inspect.v1 JSON) and inspection_url. The download contains face indices,
surface parameters, area, bounds, neighbours and verified selector objects. A null selector
has a selector_note explaining why no documented selector uniquely identifies that face.
Paste a non-null selector into a direct_edit / fillet document with the same import options.
Inspection uses the existing daily build and running-job quotas and a 240-second timeout.
The engine emits up to 2000 faces with truncated: true when more exist. Hosted inspection
JSON is capped at 4 MiB. Existing failure codes apply; failed inspections have status: "failed".
Archives and result files use the same 30-day retention as builds.
POST /api/v1/builds
{
"document": { ...VXL... },
"overrides": {"width": 40},
"timeout_ms": 240000,
"assets": {"stock": {"upload_key": "uploads/<tenant>/<uuid>"}}
}
- Optional header
Idempotency-Key: <1–128 printable ASCII>. Retrying with the same key and body returns the same build; the same key with a different body gets409 conflict. - A build uses Ingot from your balance according to how long it ran, including a build that fails. It is charged when you first read its result. A new build is refused once the balance is used up.
- Returns 202
{"build_id", "status": "queued", "status_url"}.
GET /api/v1/builds/{build_id}
Poll every 2–5 s until status is completed or failed.
{
"build_id": "…", "status": "completed", "verdict": "RELEASE",
"created_at": "…", "updated_at": "…", "wall_ms": 5967,
"summary": { ... }, "revision_packet": { ... },
"archive_url": "https://…", "expires_at": "…"
}
archive_url is a ZIP of generations/ and report/. The link is valid for 24 hours, and every
poll returns a fresh one. Results are kept for 30 days.
GET /api/v1/builds?limit=20&cursor=…
Lists your builds and inspections, newest first, without reports. If the reply has next_cursor, pass it as
cursor to get the next page.
5. Limits and quotas
| Limit | Value |
|---|---|
| Document | ≤ 1 MiB serialized |
| Overrides | ≤ 64 KiB |
timeout_ms |
≤ 240 000 (default 240 000) |
| Assets per build | ≤ 16; STEP ≤ 32 MiB in total; STL ≤ 64 MiB each and ≤ 96 MiB in total |
| Builds and inspections per day | 50 per tenant (default) |
| Concurrent builds and inspections | 2 per tenant |
| Request rate | about 50 requests per second, with bursts of 100 |
Typical time from submit to done:
- simple exact parts: 5–10 s;
- organic and mesh parts: 15–25 s;
- the first build after an idle period: add about 10 s.
6. Errors
All errors have the form {"error": {"code", "message", "detail?"}}.
| HTTP | code |
When |
|---|---|---|
| 400 | invalid_request |
Malformed body, unknown field, bad asset binding |
| 401 | unauthorized |
Missing, invalid or revoked key |
| 404 | not_found |
Unknown route, or a build that is not yours |
| 409 | conflict |
Idempotency-Key reused with a different body |
| 413 | payload_too_large |
Over a size limit |
| 429 | quota_exceeded |
Daily build quota or concurrent builds reached, or not enough Ingot |
| 503 | unavailable |
Temporary; retry with backoff |
7. Raw HTTP example
H="Authorization: Bearer $VEXTONLINE_TOKEN"
DOC=$(cat part.vxl.json)
curl -s -H "$H" -H 'content-type: application/json' \
-d "{\"document\": $DOC}" https://api.vextcad.com/api/v1/checks
ID=$(curl -s -H "$H" -H 'content-type: application/json' -H "Idempotency-Key: part-1" \
-d "{\"document\": $DOC}" https://api.vextcad.com/api/v1/builds | python3 -c 'import json,sys; print(json.load(sys.stdin)["build_id"])')
curl -s -H "$H" https://api.vextcad.com/api/v1/builds/$ID # repeat until completed
8. MCP tools
Connect to https://mcp.vextcad.com/mcp. Read the hosted mcp-workflow documentation
first. Available tools: read_docs, search_docs, check_vxl, upload_asset, describe_asset,
inspect_asset, start_build, get_build, get_preview, list_builds, get_account.
describe_asset(upload_key) returns the media_type, bytes and digest that the document's
assets[] entry needs. get_account shows your Ingot balance.
For STEP face selection: upload_asset → inspect_asset(upload_key, import) →
get_build(build_id) until terminal. The text content is a compact table of the first 200
faces: index, surface kind/parameters, area and a selector as one-line JSON. If truncated,
read the note and download inspect.json. structuredContent.inspection contains the
full v1 report up to 64 KiB; above that cap only inspection_url and an MCP resource link
carry the report. The full report can itself be truncated by the engine's 2000-face cap.
Paste verified selectors into direct_edit / fillet documents using matching import options.
9. Not yet available
The following are not available yet:
- named variants (
--variantof the local CLI); send the equivalentoverridesinstead; - revisioned editing sessions.