Support

RESTful API

Use our RESTful API to manage products, hotspots, and analytics programmatically.

API

Introduction

Our RESTful API lets you programatically create projects and products (360° views), as well as list existing projects and products.

The following guide will go through the endpoints that are required to create a 360° view.

It consists of:

  1. Create a project
  2. Create a product (360° view)
  3. Upload images
  4. Finish upload
  5. Embed
  6. List all products (360° views)
  7. List all projects
  8. List all products for a given project
  9. Update a product
  10. Delete a product
  11. Download a product’s source files
  12. List a product’s images
  13. Update image alt text

1. Create a project

All products (360° views) are grouped into projects. In order to create a product, you must first create a project and obtain a project UUID.

POST https://app.spinshot.io/api/v2/projects

Params

  • title: Project title

Example

curl -u "USER:PASSWORD" -X POST -H "Content-Type: application/json" -H "Accept: application/json" "https://app.spinshot.io/api/v2/projects" -d ' { "title": "Model cars" }'

In return, you’ll receive a JSON with the project credentials. Take special note of the project UUID, you’ll need it in the next step.

Example

{ "uuid": "sAQizc_u9gM", "title": "Model cars", "created_at": 2014-06-24T07:23:51.071Z }

2. Create a product (360° view)

Create a product and customize the viewer settings.

POST https://app.spinshot.io/api/v2/products

Params

  • title: Title
  • sku: SKU
  • manufacturer: Manufacturer name
  • year: Year
  • project: Project UUID
  • images: Number of images (“1” for video uploads)

Example

curl -u "USER:PASSWORD" -X POST -H "Content-Type: application/json" -H "Accept: application/json" "https://app.spinshot.io/api/v2/products" -d ' { "title": "VW van", "sku": "10023", "manufacturer": "Lego", "year": "2013", "project": "sAQizc_u9gM", "images": 24 }'

In return, you’ll receive a JSON with the credentials needed to upload the images.

Example

{ "uuid": "123456789", "title": "VW van", "path": "123456789/00000/1-rotation/row-1", "policy": "jAwMFonLAogICAg...", "signature": "GP35g00a3NsILoIf3...", "hostname": "upload-app.spinshot.io", "access_key_id": "KTFSMTRXEMSGR...", "acl": "private" }

3. Upload images

Upload the images to S3. Make sure that the image’s file names are sortable, as this will later provide the order for the 360 view.

https://HOSTNAME where HOSTNAME is returned by the previous call’s JSON object.

Params

  • key: PATH**/**FILENAME
  • acl: ACL
  • AWSAccessKeyId: ACCESS_KEY_ID
  • Policy: POLICY
  • Signature: SIGNATURE
  • Content-Type: image/jpeg, video/mp4, etc.
  • file: PATH_TO_FILE

Example

curl -s \ -F "key=123456789/00000/1-rotation/row-1/vw-van-01.jpg" \ -F "acl=private" \ -F "AWSAccessKeyId=KTFSMTRXEMSGR..." \ -F "Policy=jAwMFonLAogICAg..." \ -F "Signature=GP35g00a3NsILoIf3..." \ -F "Content-Type=image/jpeg" \ -F "file=@360-views/model-cars/vw-van/vw-van-01.jpg" \ https://$hostname

Repeat this step for each single image.

4. Finish upload

Notify SpinShot that the upload to S3 has completed.

POST https://app.spinshot.io/api/v2/products/UUID/uploaded

Params

  • none

Example

curl -u "USER:PASSWORD" -X POST -H "Content-Type: application/json" -H "Accept: application/json" "https://app.spinshot.io/api/v2/products/123456789/uploaded"

5. Embed

Retrieve an iframe embed URL for a 360° view.

GET https://app.spinshot.io/api/v2/products/UUID/embed

Params

  • type: “iframe” or “responsive”
  • width: maximum width
  • height: maximum height

Note: if type “responsive” is chosen, width and height will be ignored as the embed link adjusts its size responsively.

Example

curl -X GET -H "Accept: application/json" "https://app.spinshot.io/api/v2/products/123456789/embed?type=iframe&width=640&height=480"

In return, you’ll receive an iframe embed link to paste into a website.

Example

<iframe width="640" height="480" src="http://embed.spinshot.io/PQUDbEJO_N4" frameborder="0" scrolling="no" style="background-color: #fff" allowfullscreen>

Complete Upload Example

The following bash script will upload all images found in the current working directory. Use the first 5 lines to define the user and password for your account, the project UUID, the title for the product to be created, and the host for the API.

Depending on your setup, you might have to install JQ (https://jqlang.github.io/jq/)

user=<USER> password=<PASSWORD> project=<PROJECT_UUID> title=<PRODUCT_TITLE> host="https://app.spinshot.io" count=$(ls -1q * | wc -l) params='{ "title": "'$title'", "project": "'$project'", "images": "'$count'"}' command="curl -u '"$user":"$password"' -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' '"$host"https://app.spinshot.io/api/v2/products' -d '"${params}"'" result=$(eval $command) hostname=$(echo $result | jq -r '.hostname') uuid=$(echo $result | jq -r '.uuid') policy=$(echo $result | jq -r '.policy') signature=$(echo $result | jq -r '.signature') directory=$(echo $result | jq -r '.path') for f in * ; do echo "Uploading $f"; curl \ -F "key=$directory/$f" \ -F "acl=private" \ -F "AWSAccessKeyId=AKIAJLYJVDJ7RMESCYNA" \ -F "Policy=$policy" \ -F "Signature=$signature" \ -F "Content-Type=image/jpeg" \ -F "file=@$f" \ https://$hostname ; done curl -u "$user:$password" -X POST -H "Content-Type: application/json" -H "Accept: application/json" "$host/api/v2/products/$uuid/uploaded"

Listing products (360° views) and projects

6. List all Products (360° views)

Retrieve a list of all 360° views.

GET https://app.spinshot.io/api/v2/products

Params (optional)

  • title
  • manufacturer
  • sku
  • year

Example 1: filter by year

curl -u "USER:PASSWORD" -X GET -H "Accept: application/json" "https://app.spinshot.io/api/v2/products?year=2000"

Example 2: no filter

curl -u "USER:PASSWORD" -X GET -H "Accept: application/json" "https://app.spinshot.io/api/v2/products"

…returning a list of products, e.g.

[{"uuid":"123456789","title":"My product title","sku":"SKU-0001","manufacturer":"","year":null,"project":"987654321","created_at":"2019-06-03T14:11:42.410Z"}, {...}]

7. List all projects

Retrieve a list of all projects.

GET https://app.spinshot.io/api/v2/projects

Params

  • No params

Example

curl -u "USER:PASSWORD" -X GET -H "Accept: application/json" "https://app.spinshot.io/api/v2/projects"

…returning a list of projects, e.g.

[{"uuid":"123456789","title":"My project title","created_at":"2019-06-03T14:11:42.410Z", products: 5}, {...}]

8. List all products for a given project

Retrieve a list of all products within a certain project.

GET https://app.spinshot.io/api/v2/projects/UUID

Params (optional)

  • title
  • manufacturer
  • sku
  • year

Example 1: filter by year

curl -u "USER:PASSWORD" -X GET -H "Accept: application/json" "https://app.spinshot.io/api/v2/projects/PQUDbEJO_N4?year=2000"

Example 2: no filter

curl -u "USER:PASSWORD" -X GET -H "Accept: application/json" "https://app.spinshot.io/api/v2/projects/PQUDbEJO_N4"

… returning a list of products, e.g.

[{"uuid":"123456789","title":"My product title","sku":"SKU-0001","manufacturer":"","year":null,"project":"987654321","created_at":"2019-06-03T14:11:42.410Z"}

9. Update an existing product (360° view)

Updates an existing product, with the option to upload new images. Alt text for individual images is not updated here; use List a product’s images and Update image alt text for that.

PATCH https://app.spinshot.io/api/v2/products/123456789

Params

  • title: Title
  • sku: SKU
  • manufacturer: Manufacturer name
  • year: Year
  • images: Number of images (optional, to indicate a reupload)

Example

curl -u "USER:PASSWORD" -X PATCH -H "Content-Type: application/json" -H "Accept: application/json" "https://app.spinshot.io/api/v2/products/123456789" -d ' { "title": "VW van", "sku": "10023", "manufacturer": "Lego", "year": "2013", "images": 24 }'

If you provided a value for “images”, please proceed from2. Create a product

Otherwise, you’ll receive a JSON object, containing either {notice: “OK”}or{errors: […]}.

10. Delete a product

Deletes a product.

DELETE https://app.spinshot.io/api/v2/products/123456789

Params

  • No params

Example

curl -u "USER:PASSWORD" -X DELETE -H "Accept: application/json" "https://app.spinshot.io/api/v2/products/123456789"

You’ll receive a JSON object, containing either {notice: “OK”} or {errors: […]}.

11. Download a product’s source files

Downloads all source files for a product.

GET https://app.spinshot.io/api/v2/products/123456789.zip

Params

  • No params

Example

curl -u "USER:PASSWORD" -X GET -H "Accept: application/zip" "https://app.spinshot.io/api/v2/products/123456789.zip"

You’ll receive a ZIP-file if successful, or a JSON containing {errors: […]}.

12. List a product’s images

Returns a JSON array of images for a product, including id, ordial, alt_texts, storage metadata, and Media CDN URLs. Use the image id when updating alt text via Update image alt text.

Compatibility note: The former name field has been removed. Use the numeric ordial for sequence ordering and source for the actual stored filename; do not derive filenames from ordial.

Uses the existing HTTP Basic authentication and requires edit permission for the product’s project. Responses use Cache-Control: no-store. An empty product returns []. Image records remain in the response while processing, so their IDs and alt texts are still available even when media URLs are not ready.

GET https://app.spinshot.io/api/v2/products/UUID/images

Params

  • No params

Example

curl -u "USER:PASSWORD" -X GET -H "Accept: application/json" "https://app.spinshot.io/api/v2/products/123456789/images"

Illustrative response (all identifiers, filenames, and the reserved example hostname below are fictional, not customer values):

[ { "id": 101, "ordial": 1, "alt_texts": {"en": "Front view"}, "source_revision": 0, "storage_version": 1, "image_status": "finished", "source": "sample front.jpg", "row": 1, "image_group": "rotation", "media_ready": true, "media_url": "https://media.example.com/example-account/frames/example-product/0;1;sample%20front.jpg", "thumbnail_url": "https://media.example.com/example-account/frames/example-product/0;1;sample%20front.jpg/resize;w_320/image.webp" } ]

Response fields

Field Meaning
id Image ID, used for updating alt text.
ordial Numeric sequence position (spelled ordial); not the source filename. Images are returned in this order.
alt_texts Locale-to-alt-text mapping.
source_revision The variant’s current upload revision, including valid revision 0; not a guarantee that processing has finished.
storage_version The variant’s storage version, which determines the media path layout.
image_status The product/variant’s current image processing status.
source The actual stored source filename or path. For example, the image at ordial: 1 may reference source: "4.jpg".
row This image’s stored row; do not substitute a product-level row or assume every image is row 1.
image_group This image’s stored group, such as rotation, additional, or gallery.
media_ready Boolean: true only when the product’s image_status is finished and usable image-path and account metadata are available. Otherwise false.
media_url Absolute HTTPS base URL using the account’s media host, account public UUID, and image.image_path, with source path segments URL-encoded. No trailing slash, transformations, or output filename; append these to request an image. null unless media_ready is true.
thumbnail_url Ready-to-use thumbnail: media_url plus /resize;w_320/image.webp, requesting a 320 px wide WebP with the source aspect ratio preserved. null unless media_ready is true.

These URLs use the current Flyster media stack. Storage v1 uses frames/{product_uuid}/{revision};{row};{source}, stills/{product_uuid}/{revision};{source}, or gallery/{product_uuid}/{revision};{source}. Storage v2 uses images/{product_uuid}/{source} with no revision in the path, even though source_revision is returned as metadata.

Use media_url when building custom sizes or formats: append the desired Media CDN transformation segments and output filename. For example, append /resize;w_1200/image.webp for WebP. media_url is a base for constructing requests, not a ready-to-display image URL. Use thumbnail_url directly for previews; do not append transforms to it, since it already includes an output filename. Neither URL automatically applies viewer settings or watermarks; the thumbnail adds only the fixed resize and WebP output.

Readiness and reshoots

The response describes the latest state at the request snapshot, not a permanent link to whichever upload is newest later. Refetch the image list after reshoots or reuploads: image IDs and stored source filenames can change. Do not synthesize a path by incrementing a revision or replacing a filename.

While processing (or when required path/account metadata is unavailable), each image record still includes its alt-text fields, but has "media_ready": false, "media_url": null, and "thumbnail_url": null.

To poll processing status, use GET https://app.spinshot.io/api/v2/products/UUID/status. This existing status endpoint is public; unlike /images, it does not require authentication or project edit permission:

curl -X GET -H "Accept: application/json" "https://app.spinshot.io/api/v2/products/123456789/status"

Read variant.source_revision and variant.image_status in the status response (variant is null for an unknown product). Status responses use Cache-Control: no-cache, requiring revalidation, rather than the image listing’s no-store policy. Poll with backoff rather than a tight loop. The revision increments before media is ready, so a new revision alone is not a readiness signal. Once variant.image_status is finished, refetch /images and use only entries with media_ready: true; do not construct URLs from the status response.

13. Update image alt text

Updates the alt text (accessibility description) for a specific image of a product. Use List a product’s images to get the image id for the product.

PATCH https://app.spinshot.io/api/v2/images/IMAGE_ID

Params (JSON body)

  • alt_texts: Object mapping locale codes to alt text strings, e.g. {"en": "Front view", "de": "Ansicht von vorne"}. Send the full object; it replaces all alt texts for this image. Empty or blank values are omitted from the stored result.

Example

curl -u "USER:PASSWORD" -X PATCH -H "Content-Type: application/json" -H "Accept: application/json" "https://app.spinshot.io/api/v2/images/101" -d ' { "alt_texts": { "en": "Front view of product", "de": "Ansicht von vorne" } }'

You’ll receive a JSON object with the updated image, e.g. { "id": 101, "variant_uuid": "123456789", "alt_texts": { "en": "Front view of product", "de": "Ansicht von vorne" } }, or { "errors": [...] } on failure.

Can't find what you're looking for?

Search our knowledge base for specific topics and solutions.

Still have questions?

Our support team is here to help you get started with SpinShot.

Contact Support