12 KiB
6.6. Cloud REST API
HTTPS to Bambu’s cloud (api.bambulab.com / .cn, plus S3/OSS for uploads) — not a TCP service on the printer. The plugin and Studio use it for account and fleet features that sit beside the LAN channels in §6.
This page is the shared transport contract: hosts, mandatory headers, fingerprint headers, and the common response envelope. Per-ABI symbol mappings live under §8.5–§8.15 and §8.10; print pipeline: §8.8.
What it is for
| Area | Examples |
|---|---|
| User session | Ticket / OAuth login, refresh token, profile |
| Printer inventory | List / bind / rename; plaintext dev_access_code for LAN unlock |
| Shared app credentials | Cert endpoint (app chain / CRL / key blob) for signing, app_cert_install, HTTP PoP |
| Cloud print | Project create, presigned upload, POST /my/task dispatch |
| Camera remote | ttcode / TUTK UID minting (§6.7) |
| Content / sync | User presets, Filament Manager, MakerWorld / Mall, tracking |
Does a LAN-Only printer need it?
No for direct device control. SSDP + access code from the printer screen + LAN MQTT / FTPS / :6000 / RTSP is enough to discover the printer, open sessions, upload, and print locally.
Cloud REST is needed for: signing in, fetching access codes without the screen, cloud-dispatched print, shared app-cert fetch (stock secured path), remote TUTK camera, cloud history / MakerWorld, and plugin OTA manifests. A headless LAN-Only setup with a manually entered code never has to call api.bambulab.*.
Regional hosts
Chosen by the user's country_code in app_config (the same switch GUI_App::get_http_url uses for the plugin manifest, see §2.1):
| Region | API host | Web host |
|---|---|---|
US / default |
https://api.bambulab.com |
https://bambulab.com |
CN |
https://api.bambulab.cn |
https://bambulab.cn |
Paths in §8 chapters are relative to the regional API host unless noted.
Common request requirements
| Requirement | Rule |
|---|---|
| Host | Regional API host above (set_country_code / Studio country_code) |
| Auth | Authenticated routes: exactly Authorization: Bearer <access_token> |
| Body | When sending JSON: Content-Type: application/json |
| TLS | Normal public CA trust for api.bambulab.* (not the LAN printer.cer path) |
Unauthenticated ticket-login steps mint the bearer; afterwards every cloud REST surface in the networking plugin uses that token unless a chapter says otherwise.
Headers
Authentication
Authorization: Bearer <access_token>
Fingerprint headers
MITM/SSLKEYLOGFILE captures of the stock plugin show the full fingerprint header set on every request:
User-Agent: bambu_network_agent/<agent-ver>
X-BBL-Client-Name: BambuStudio
X-BBL-Client-Type: slicer
X-BBL-Client-Version: <slicer-ver>
X-BBL-Device-ID: <slicer-machine-uuid>
X-BBL-Language: en-US
X-BBL-OS-Type: linux
X-BBL-OS-Version: <os-build, e.g. 10.0.26200>
X-BBL-Agent-Version: <agent-ver>
X-BBL-Executable-info: {}
X-BBL-Agent-OS-Type: linux
X-BBL-Client-Version is the slicer version; X-BBL-Agent-Version is the networking plugin version. X-BBL-OS-Type and X-BBL-Agent-OS-Type both report linux when running through pjarczak's WSL2 bridge; native Linux builds send linux directly. X-BBL-OS-Version carries the OS build string (Windows build number when relayed through pjarczak). X-BBL-Executable-info is the literal string {} on the Linux captures above; stock Windows Studio sends a code-signing JSON for the signed executable instead (subject Shanghai Lunkuo Technology Co., Ltd, GlobalSign EV CodeSigning — #112, mitmproxy 2026-10-05). X-BBL-Device-ID is a machine-local UUID, not the printer serial.
Plus anything Studio injects through bambu_network_set_extra_http_header (§8.10). Direct probes against the production server confirm that none of the X-BBL-* headers, nor even the custom User-Agent, are required for most endpoints (auth, profile, presets, bind, project/upload) — there they influence analytics only.
Exception —
POST /v1/user-service/my/task(cloud print / "local print with record"). On live hardware two of these headers are hard requirements; without them the endpoint returns HTTP 403 ("no access rights to the content") and the cloud print never starts:
X-BBL-Client-Name: BambuStudio— MakerWorld's user-service authorizes access to the just-uploaded print content only for the stock client identity. Other client-name values are rejected with 403.X-BBL-OS-Type— must match the OS that performed the upload (linux/windows/macos); a mismatch also 403s.Subtractive bisection against the production server (2026-07) narrowed the requirement to exactly these two
X-BBL-*headers; the remaining fingerprint headers stay analytics-only even on/my/task. The signed command-security headers (x-bbl-app-certification-id,x-bbl-device-security-sign) are additionally needed for a secured printer — see §10.5 and §8.8.3.
Exception —
POST /v1/iot-service/api/user/ttcode(camera mint). NeedsX-BBL-Client-Name: BambuStudio, anX-BBL-OS-Typethat matches the app leaf, and the PoP headers (x-bbl-app-certification-id,x-bbl-device-security-sign, §10.5), regardless of the printer's Developer Mode. On a strict account a missing or rejected PoP is HTTP 403{"code":8,"error":"The specified resource is forbidden. …"}(P2S, 2026-09; X2D, 2026-10). On a lenient account the same call returns 200 and the cloud pushes a cleartextpreparethat secured firmware rejects (§10.3). A client without an accepted PoP therefore does not get a usable cloud camera on secured firmware.Which PoP the cloud accepts is bound to the app leaf's platform, not to the account and not to a release channel (§10.2). Live matrix (one account, 2026-10-05 / 2026-10-06; the same split on a second account in #112):
Leaf X-BBL-OS-TypeX-BBL-Executable-infoHTTP Linux a4e8faaa(CN=…-836763c70000)linux{}or the Windows EV JSON200 Linux a4e8faaawindows/macos{}or the Windows EV JSON403 code:8Windows 4a63194e(CN=…-eed1e0410000)windowsreal EV JSON (as stock Windows sends it) 200 Windows 4a63194ewindows{}or absent403 code:8Windows 4a63194elinuxreal EV JSON 403 code:8
X-BBL-Client-Version,X-BBL-Language,X-BBL-Agent-OS-TypeandX-BBL-Client-IDdo not change the outcome; onlyX-BBL-OS-Typehas to match the leaf, and the Windows leaf additionally requires a non-emptyX-BBL-Executable-info. An earlier reading that the Windows leaf was rejected outright came from sending it aslinuxwithX-BBL-Executable-info: {}. Stock release Windows Studio02.08.02.61presents the Windows leaf withX-BBL-OS-Type: windowsand the EV JSON and gets 200. The cloud is still not equally strict about a missing PoP: some accounts get 403, others get 200 and a cleartext dispatch the printer rejects (§10.3).TODO: what makes the cloud lenient (
200without an accepted PoP) for some accounts, and whether a macOS leaf exists with the same OS-Type binding.
Device-scoped X-BBL-Client-ID
An additional header X-BBL-Client-ID appears on device-scoped endpoints (e.g. firmware version query, device metadata) but not on account-scoped endpoints (auth, profile, presets):
X-BBL-Client-ID: slicer:{user_id}:{4-char-suffix}
user_id is the numeric user ID (same as uidStr in the profile response). The 4-character suffix appears to be a random or session-derived nonce; its exact derivation is unconfirmed. This header is not required for the API to accept the call.
Common JSON envelope
Most JSON responses share:
{
"message": "success" | "<human message>",
"code": null | <integer error>,
"error": null | "<string>",
"...endpoint-specific fields..."
}
code is the "business" error code the GUI inspects (for example 14 for preset quota exceeded, 2 for missing resources). Transport-level failures surface as non-2xx HTTP codes — typically 400 for malformed bodies, 401 for a missing/expired bearer, 422 for invalid-input (e.g. PATCH against an unknown ID), 5xx for server-side failures.
For endpoints that return a plain-text error (notably POST /slicer/setting with a missing mandatory field) the body is a bare string — the envelope is absent.
Where the REST surfaces live
| Concern | Endpoint(s) | Section | Evidence |
|---|---|---|---|
| Bearer-token login / refresh / profile / logout | POST /v1/user-service/user/ticket/<T>, POST /v1/user-service/user/refreshtoken (body {"refreshToken":…}), GET /v1/user-service/my/profile, POST /v1/user-service/my/logout (body {"refreshtoken":…}, on user_logout(true)) |
§8.5 (§8.5.1, §8.5.14) | MITM + probe |
| Device account bind / pin bind / unbind | Account bind cloud: GET+POST /v1/user-service/my/ticket/<T> (device ticket; LAN mint is TCP :3000 login, §8.6.3); pin: POST /v1/user-service/my/pincode/<PIN> body {"pincode":…}; unbind: DELETE /v1/iot-service/api/user/bind body {"dev_id","force"} |
§8.6 (§8.6.3–§8.6.5) | MITM + LAN pcap (stock 2026-07) |
Bind ownership query (query_bind_status) |
GET /v1/iot-service/api/user/bind_list?dev_ids=<id>[,…] (not /user/bind) |
§8.6.7 | MITM probe (stock_query_bind.mitm) |
| WebView SSO ticket | GET /v1/user-service/user/ticket then POST /v1/user-service/my/ticket/<T> |
§8.6.6 | MITM |
| Device list / rename (not bind ABI) | GET /v1/iot-service/api/user/bind, PATCH /v1/iot-service/api/user/device/info (also GET …/user/print) |
§8.10 | MITM + probe |
| Printer firmware catalogue | stock: GET /v1/iot-service/api/user/device/version?dev_id=<serial> (add X-BBL-Client-ID: slicer:<uid>:<4-char-suffix>) |
§8.7 | SSLKEYLOGFILE (stock) |
| Cloud print-job pipeline | POST /v1/iot-service/api/user/project, PUT <presigned>, …, POST /v1/user-service/my/task |
§8.8.3 | MITM |
Generic HTTP ABI (get_user_tasks, …) |
see per-symbol list | §8.10 | MITM + probe |
| User presets sync | <m> /v1/iot-service/api/slicer/setting[/<id>]?public=false&version=<bundle> |
§8.9 | MITM + probe |
| Filament Manager (spool catalogue) | ` /v1/design-user-service/my/filament/v2[/batch | /ams/sync], GET /v1/design-user-service/filament/config` |
§8.15 |
| MakerWorld / Mall, OSS upload | GET …/design-user-service/my/preference, GET …/design-service/my/design/recommend, GET …/user-service/my/task/<id>, GET/PUT …/comment-service/rating[/inst]/…; GET …/ossconfig?useType=1 + client-signed object PUT |
§8.12 | MITM mw_probe (preference / recommend / rating / my/task); OSS object-key TODO |
| Camera / live view / HMS snapshot | POST /v1/iot-service/api/user/ttcode (liveview mint; PoP required, see above); go-live / get_hms_snapshot endpoints still open |
§8.11 | MITM + live probe (ttcode); go-live / HMS TODO |
| Analytics / telemetry | GET /v1/analysis-st/tag/?UID=… → {tag,secret,iv}; GET /v1/iot-service/api/user/upload?event_track/slicer=<file>.zip.enc → presigned URL; PUT encrypted blob to S3 |
§8.13 | MITM stock_track_cold.mitm |
Hub: §6.