API Reference
/
PATCH /v1/splats/{id}
PATCH /api/v1/splats/{splatId}
Update the title, description, or visibility of a splat owned by the supplied external user — or toggle the integration-level featured flag on any splat of the integration.
PATCH
https://moshpit.studio/api/v1/splats/{splatId}
Auth
For metadata updates (title, description, visibility) all three headers are required — those fields only mutate splats owned by the external user identified in the request:
Plain
Authorization: Bearer msk_YOUR_SECRET_KEY
X-Moshpit-Public-Key: mpk_YOUR_PUBLIC_KEY
X-Moshpit-External-User-Id: YOUR_HOST_USER_IDThe splat must belong to the same embedIntegrationId as the keys, and its externalUserId must match the header value. Otherwise the response is 404 (we never reveal whether a splat exists outside of the caller's scope).
featured is different: it is a curation act by the integration, not the splat owner, so it authenticates with the key pair alone (the external-user header is optional and ignored for scoping) and works on any splat of the integration — including splats owned by your end users. See Featuring a splat.
REST API access
REST API access is included on Free, Pro, and Enterprise. Storage, Scene counts, and integration limits still apply.
Body
JSON
{
"title": "Updated title",
"description": "Optional new description",
"visibility": "public"
}| Field | Type | Description |
|---|---|---|
title | string | Trimmed; 1–200 characters. Optional. |
description | string | Up to 2000 characters. Pass `""` to clear. Optional. |
visibility | "private" | "public" | New visibility. Optional. |
featured | boolean | Integration-level curation flag. Must be the ONLY field in the request body. Optional. |
At least one field must be present. Omitted fields are left untouched. featured cannot be combined with the other fields in one request — they use different authority scopes.
Example request
Bash
curl -X PATCH "https://moshpit.studio/api/v1/splats/65f1a2b3c4d5e6f7a8b9c0d1" \
-H "Authorization: Bearer msk_YOUR_SECRET_KEY" \
-H "X-Moshpit-Public-Key: mpk_YOUR_PUBLIC_KEY" \
-H "X-Moshpit-External-User-Id: host_user_123" \
-H "Content-Type: application/json" \
-d '{"title":"Living room — final","visibility":"public"}'Success response — 200 OK
Returns the updated splat in the same shape as a list-splats item:
JSON
{
"status": "success",
"splat": {
"id": "65f1a2b3c4d5e6f7a8b9c0d1",
"title": "Living room — final",
"description": "Optional new description",
"imageUrl": "https://...",
"splatUrl": "https://...",
"visibility": "public",
"allowEmbed": true,
"allowComments": true,
"allowReactions": true,
"allowClone": false,
"remixedFrom": null,
"splatType": "lod",
"externalUserId": "host_user_123",
"productSlug": "moshpit.studio",
"isOwner": true,
"viewCount": 42,
"likeCount": 3,
"fileSizeBytes": 17825792,
"createdAt": "2026-04-12T18:30:00.000Z",
"updatedAt": "2026-05-19T11:02:14.000Z"
}
}Featuring a splat
Mark a splat for your product's curated surfaces (for example a gallery's
Featured rail). Send featured as the sole body field; the external-user
header is not required:
Bash
curl -X PATCH "https://moshpit.studio/api/v1/splats/65f1a2b3c4d5e6f7a8b9c0d1" \
-H "Authorization: Bearer msk_YOUR_SECRET_KEY" \
-H "X-Moshpit-Public-Key: mpk_YOUR_PUBLIC_KEY" \
-H "Content-Type: application/json" \
-d '{"featured":true}'Rules:
- Only
publicsplats withallowEmbed: truecan be featured — otherwise the response is409. - Featuring is idempotent: re-featuring an already-featured splat keeps its original
featuredAt, so curation order is stable. {"featured":false}clears the flag at any time.- Fetch the curated set with GET /v1/splats?featured=true&sort=featuredAt&dir=desc.
Error responses
| Status | Cause |
|---|---|
| 400 | Invalid JSON body, no updatable fields supplied, validation failure, or featured combined with other fields |
| 401 | Missing or invalid Bearer / public-key combination |
| 403 | Plan doesn't include cloning quota re-check on first publish (plan_limit) |
| 404 | Scene not found OR not owned by the supplied external user (metadata updates) / not in the integration (featured) |
| 409 | featured: true on a scene that is private or has embedding disabled |
| 413 | Storage quota exceeded on first publish (STORAGE_QUOTA_EXCEEDED) |
Publishing a clone for the first time re-checks quota
A clone created by POST /v1/splats/{splatId}/clone
doesn't count against the account's maxSplats or the external user's
per-customer scene cap while it stays private and unpublished. The first
PATCH that sets visibility: "public" on that clone re-checks both limits
and can return the same 403 plan_limit (dimension: "splatCount") or
413 STORAGE_QUOTA_EXCEEDED response a fresh upload would. Once published,
the slot is consumed permanently — unpublishing it again does not free it back
up.
What's next
- DELETE /v1/splats/{splatId} — permanently delete an owned splat.
- GET /v1/splats — list the user's full library.
- POST /v1/splats/{splatId}/clone — duplicate or remix a scene.