MCP & API
back to documentation

MCP & API

Connect supported external workflows and use the REST API reference safely.

Asset Uploads

The public asset workflow has two steps:

  1. Ask Portals for a temporary upload destination.
  2. Upload the reviewed file bytes to that destination, then use the returned location only in the supported follow-up workflow.

Temporary upload destinations expire after 60 seconds. They are sensitive operational data: do not log or publish them.

All three request routes use the x-api-key header. Their successful response has the same field names:

{
  "signedUploadURL": "temporary credential-bearing upload destination",
  "assetURL": "returned asset location",
  "objectKey": "storage identifier"
}

Use assetURL only in the documented follow-up workflow. It is not a promise of permanent storage, a reusable cross-project identifier, or a public API identifier. Do not assume objectKey is stable or usable outside the response that returned it.

JSON room-data files

POST /api/v2/utils/generate-json-upload-url

Required header: x-api-key

The handler has no required request-body field. It generates the storage name itself.

The resulting upload expects JSON bytes with this header:

Content-Type: application/json

Use this route when preparing a room-data snapshot for the room import workflow. The import handler can delete a JSON object served from the service-managed CDN after a successful import, so keep your original backup elsewhere.

GLB models

POST /api/v2/utils/generate-gltf-upload-url

Required header: x-api-key

Request body:

{
  "fileType": "model/gltf-binary",
  "fileName": "optional-name.glb",
  "enableDraco": false
}

fileType must be exactly model/gltf-binary. The route accepts only GLB binary uploads; it does not accept a generic GLTF JSON document.

Upload the returned destination with the model’s raw bytes and:

Content-Type: model/gltf-binary

The route accepts enableDraco as a boolean, but it does not transform the uploaded file. Prepare any compression before you upload. At URL issuance, the handler validates fileType; it does not add a GLB Content-Type constraint to the signed upload request. Send the matching header as good upload hygiene, but do not rely on the signing step to reject a mismatched GLB upload header.

Images

POST /api/v2/utils/generate-image-upload-url

Required header: x-api-key

Request body:

{
  "fileType": "image/png"
}

The accepted fileType values are:

Type MIME value
JPEG image/jpeg or image/jpg
PNG image/png
GIF image/gif
WebP image/webp

Upload the returned destination with the raw image bytes and the same MIME value you supplied in fileType. At URL issuance, the handler validates fileType; it does not add an image Content-Type constraint to the signed upload request. Use the matching header, but validate the file before requesting a destination.

The public contract does not require a room identifier for this route. Do not send undocumented folder overrides.

Safe upload checklist

  1. Validate the file type before requesting a destination.
  2. Request the destination only when the file is ready; it expires after 60 seconds.
  3. Use the matching Content-Type on the upload request.
  4. Check the upload response before using assetURL in the immediately intended workflow.
  5. Keep the temporary upload destination out of logs, source control, and screenshots.
  6. Test the final asset in a disposable game before referencing it from a live game.

Common failure causes

Symptom Likely cause
400 type-not-allowed response The MIME value is not on the route’s allowlist.
403 response The personal credential is missing or invalid.
Upload request fails after issuance The temporary destination expired or the upload Content-Type did not match the file workflow.
429 response for a model or image request The creator’s current daily upload allowance has been reached.

For connected asset workflows, begin with MCP setup. For placing an asset in a game, use Build Your Game.