maichine public API
Base URL: https://<your-maichine-origin>
Thin integration surface: authentication, projects, versions, color mapping, quotes, and production. Everything an agent needs for a normal task is available; nothing prescribes how the agent creates the model.
Authentication
Bearer API key from the Integrations panel:
Authorization: Bearer mk_live_...
Keys are shown once. Store as MAICHINE_KEY; never commit or print it.
/api/public/v1/capabilities is public (no auth). Every other endpoint
requires a key.
Errors
JSON with an HTTP status code, a stable machine code, and — for uploads
— structured findings[]:
{ "error": "…", "code": "TOO_LARGE", "findings": [{ "code": "TOO_LARGE", "message": "…" }] }
Common statuses: 400 invalid input · 401 missing/invalid key · 403
missing scope · 404 project not found · 413 upload too large · 415
extension not allowed · 429 rate or daily-quota exceeded.
GET /api/public/v1/bootstrap
Authenticated. One request returns account info, capabilities version, upload formats and limits, the live production color palette, and every endpoint URL. Cache for the current task.
{
"authenticated": true,
"account_id": "…",
"capabilities_version": "…",
"formats": { "upload": ["stl","3mf"], "multicolor_preferred": "3mf" },
"limits": { "max_upload_bytes": 26214400 },
"production_colors": [ { "id": "10101", "name": "Black", "hex": "#000000" }, … ],
"endpoints": {
"projects": "https://…/api/public/v1/projects",
"versions": "https://…/api/public/v1/projects/{id}/versions",
"version_status": "https://…/api/public/v1/projects/{id}/versions/{versionId}",
"update_colors": "https://…/api/public/v1/projects/{id}/color-mapping",
"quotes": "https://…/api/public/v1/quotes",
"production_requests": "https://…/api/public/v1/production-requests",
"credits_balance": "https://…/api/public/v1/credits/balance"
},
"production_api": { "status": "available", "message": "…" }
}
GET /api/public/v1/capabilities
Public. Full machine-readable capabilities feed. Cacheable for 5 minutes;
honors If-None-Match via the ETag header.
POST /api/public/v1/projects
Create a project.
{ "name": "Desk lamp base", "description": "optional", "agent": "optional" }
Response 201:
{
"project_id": "…",
"slug": "desk-lamp-base",
"name": "Desk lamp base",
"preview_url": "https://…/preview/<preview_slug>",
"upload_url": "https://…/api/public/v1/projects/<id>/versions"
}
POST /api/public/v1/projects/{id}/versions
Upload a new model version as multipart/form-data.
Fields:
file— required..stlor.3mf, up to 25 MB. Other formats are rejected withFORMAT_NOT_PRODUCTION_SUPPORTED.notes,agent,prompt— optional context strings.
Response 201 (200 if the byte hash duplicates an existing version):
{
"version": { "id": "…", "version_number": 3, "print_eligible": true, "security_status": "passed" },
"preview_url": "https://…/preview/<preview_slug>",
"status_url": "https://…/api/public/v1/projects/<id>/versions/<version_id>",
"duplicate": false,
"color_mapping_complete": true,
"parts": [
{ "part_key": "base", "name": "Keychain Base", "design_color": "#000000", "production_color_id": "10101" },
{ "part_key": "logo", "name": "Gemini Spark", "design_color": "#0086D6", "production_color_id": "10603" }
]
}
Use parts[].part_key for later color changes — do not re-upload.
GET /api/public/v1/projects/{id}/versions
Newest first. Each entry includes status, security_status,
print_eligible, and a status_url for polling.
GET /api/public/v1/projects/{id}/versions/{versionId}
One version's metadata.
PATCH /api/public/v1/projects/{id}/color-mapping
Change production colors on an existing version without re-uploading.
Requires scope versions:write.
{
"version_id": "ver_…",
"updates": [
{ "part_key": "logo", "production_color_id": "10200" }
]
}
Response:
{
"project_id": "…",
"version_id": "…",
"color_mapping_complete": true,
"parts": [ { "part_key": "logo", "production_color_id": "10200", "name": "Gemini Spark", "design_color": "#0086D6" } ],
"preview_url": "https://…/preview/<preview_slug>"
}
Error codes: UNKNOWN_PART_KEY (returns available_part_keys),
PRODUCTION_COLOR_UNAVAILABLE. Any non-terminal quote on the version is
invalidated (declined) — the human must re-confirm before production.
Production API
Requires matching scopes on the API key. Every quote requires explicit
human approval via confirmation_url before it can be submitted.
GET /api/public/v1/credits/balance—credits:read.GET /api/public/v1/production/options—production:read.POST /api/public/v1/quotes—production:read. Returns{ quote_id, confirmation_url, ... }.POST /api/public/v1/production-requests—production:write. Requires a confirmedquote_idand a uniqueIdempotency-Keyheader.