Skip to main content
Unlisted page
This page is unlisted. Search engines will not index it, and only users having a direct link can access it.

Splat Publishing

Overview

Publish a splat (e.g., .ply or .sog) to the SuperSplat platform programmatically — the same backend used by the Editor's Publish dialog and the Direct Upload flow on superspl.at. Once published, the splat appears on the user's Manage page and can be opened in Studio to curate its viewing experience.

The settings field on the publish call carries the Experience Settings JSON — the same contract Studio writes and the SuperSplat Viewer reads. See that reference for the full schema.

The flow consists of three main steps:

  1. Request a signed upload URL from the backend.
  2. Upload the file directly to S3 using that signed URL.
  3. Start the processing job by calling the backend API.

All API requests must include a valid Bearer token in the Authorization header. Check this document to read about allocating a token.

Routes

Get Signed URL for AWS S3 upload

POST https://playcanvas.com/api/upload/signed-url

Body

{ "fileName": "scene.ply" }

Response

{ "signedUrl": "string", "s3Key": "string" }

Example:

const response = await fetch(`https://playcanvas.com/api/upload/signed-url`, {
method: 'POST',
body: JSON.stringify({
fileName: filename
}),
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});

Upload to AWS S3 using signed url

PUT "signedUrl"

Response

{ "signedUrl": "string", "s3Key": "string" }

Example:

const uploadResponse = await fetch(signedUrl, {
method: 'PUT',
body: fileData,
headers: {
'Content-Type': 'binary/octet-stream'
}
});

Start processing

POST https://playcanvas.com/api/splats/publish

Body

{
"s3Key": "string",
"title": "string",
"description": "string",
"listed": boolean,
"settings": { /* Settings */ },
"format": "compressed.ply" // or "sog"
}

Settings:

const settings = {
camera: {
fov: 65, // field of view
position: [1,1,-1], target: [-0.1,0.6,-0.2],
startAnim: 'none',
animTrack:null
},
background: {
color: [0.4,0.4,0.4]
},
animTracks:[]
};

Response (Splat data)

{
"id": "string",
"hash": "string",
"title": "string",
"description": "string",
"format": "compressed.ply | sog",
"version": "string",
"release_notes": "string",
"thumbnails": number,
"size": number,
"views": number,
"comments": number,
"starred": number,
"listed": boolean,
"completedAt": DateTime,
"createdAt": DateTime,
"modifiedAt": DateTime
}

Example:

const response = await fetch(`https://playcanvas.com/api/splats/publish`, {
method: 'POST',
body: JSON.stringify({
s3Key: s3Key,
title: 'Some Title',
description: 'Some Description',
listed: true,
settings: settings,
format: format
}),
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});

Sample response

{
"comments": 0,
"completedAt": null,
"createdAt": "2025-10-21T12:42:13.331Z",
"currentVersion": 1,
"description": "Some Description",
"featuredWeight": 0,
"format": "",
"hash": "982a2820",
"hasThumbnails": false,
"id": 50,
"listed": true,
"modifiedAt": "2025-10-21T12:42:13.331Z",
"releaseNotes": null,
"size": 0,
"starred": 0,
"tags": [],
"task": { "status": "running", "message": "" },
"title": "Some Title",
"url": "https://superspl.at/view?id=982a2820",
"userId": 7,
"version": 0,
"views": 0
}

Status - 201 Success

Check the status of uploaded splat

GET https://playcanvas.com/api/splats/{ID}

Response (Splat)


{
"id": "string",
"hash": "string",
"title": "string",
"description": "string",
"format": "compressed.ply | sog"
}

Example:

const response = await fetch(`https://playcanvas.com/api/splats/1000`)

Errors

CodeDescription
400Bad request / invalid payload / over storage allowance
401Unauthorized (missing/invalid token)
403Forbidden
404Resource not found (e.g., sceneId)
5xxServer/S3 error during upload or finalize