VextCAD

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: false means the document has errors. report.message names 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"}.

  • PUT the exact file bytes to put_url, with put_headers, within 15 minutes.
  • Pass upload_key to 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 gets 409 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 (--variant of the local CLI); send the equivalent overrides instead;
  • revisioned editing sessions.