Transform a vehicle

Send raw images and/or video for one vehicle and get studio-grade outputs.

Send raw images and/or video for one vehicle. Spyne returns studio-grade images, a 360 spin and a feature video from the same request.

Submits vehicle images or video for asynchronous processing into catalog images, a 360 spin, a feature video, or media kit assets.

POSThttps://api.spyne.ai/api/pv1/merchandise/process
AuthBearer tokenRate limit200 requests / minProcessingAsynchronous

Prefer ReadMe's own explorer? Open it here.

Before you call it

Provide at least one vehicle identifier. Any one of the following is sufficient:

  • vin: the vehicle's 17-character alphanumeric VIN
  • stockNumber: the dealer's internal inventory identifier
  • registrationNumber: the vehicle's official registration number

Processing is asynchronous. A 202 response confirms only that the request was accepted and returns a dealerVinID. Retrieve the output later with the Retrieve Media endpoint, or receive it by webhook.

Image URLs are validated before processing begins. A maximum of 200 URLs is accepted per request, each must use the http or https scheme, and each must return a 2xx or 3xx status when fetched. Duplicate URLs are collapsed.


Request body

Requiredalways sendAt least onesend one or more from the groupOptionalcan be left outRequired ifrequired only when the matching output is selected
Request checklist
  1. Identify the vehicle: send at least one of vin, stockNumber or registrationNumber.
  2. Pick an output: in media, set at least one of image, spin or featureVideo to true. mediaKit is optional.
  3. Send the files: in mediaInput, send imageData, videoData or both.
  4. Configure each output you picked: processingDetails.backgroundId is always required. media.image needs processingDetails.image, media.spin needs processingDetails.spin and media.featureVideo needs processingDetails.featureVideo.
ParameterTypeRequiredDescription
Vehicle identifier—RequiredSend at least one of the three fields below. Use vin when you have it.
vinstringAt least oneThe unique 17-character VIN of the vehicle.
stockNumberstringAt least oneA dealer's internal identifier for inventory tracking
registrationNumberstringAt least oneThe vehicle's official registration number used for identification
mediaobjectRequiredThe outputs to generate. Set at least one of image, spin or featureVideo to true. mediaKit is optional and can be added to any of them.
media.imagebooleanAt least oneSet to "true" to process the vehicle images into a studio-ready format
media.spinbooleanAt least oneSet to "true" to create a 360° spin for the vehicle
media.featureVideobooleanAt least oneSet to "true" to generate a feature video highlighting key vehicle details
media.mediaKitbooleanOptionalSet to "true" to generate media kit assets for the vehicle
mediaInputobjectRequiredThe source files to process. Send imageData, videoData or both.
mediaInput.imageDataobject[]At least oneAn array of URLs pointing to the images to be processed for studio-ready outputs.
mediaInput.imageData[].urlstringRequiredURL of the image. Required in every entry; an entry without a URL is ignored.
mediaInput.imageData[].clientMetaDataobjectOptionalOpaque per-image metadata. Stored against the asset and echoed back unchanged on Retrieve Media. Spyne does not interpret these keys.
mediaInput.videoDataobject[]At least oneAn array of URLs pointing to videos, primarily used for generating 360° spins or feature videos. Only "url" is read; any other keys are ignored.
mediaInput.videoData[].urlstringRequiredPublicly reachable source video URL. Required in every entry; an entry without a URL is ignored.
processingDetailsobjectRequiredSettings for the outputs you selected in media. backgroundId is always required, and each selected output needs its own settings object.
processingDetails.numberPlateLogostringOptionalIt specifies the treatment for the vehicle’s number plate. You can also Pass "0" for no number plate masking, "1" for a plain white masking, or a "URL" to use a custom number plate masking
processingDetails.backgroundIdstringRequiredIdentifier for the background to composite behind the vehicle. This ID is created by the Spyne team. Required for every request: without it the request comes back as a 206 carrying error code "VAL_CONFIG_001". Example: 75282.
processingDetails.imageobjectRequired ifConfigurations to generate a catalog-ready images of the vehicle. Required when media.image is true. If it is missing, that output is skipped and the response is a 206 with error code "VAL_CONFIG_004". Send an empty object to use the defaults.
processingDetails.image.catalogCountintegerOptionalThe number of catalog images to generate. Defaults to 8 when omitted. "Note": this is only needed when a video input is provided; for image input it can be left blank. Default: 8.
processingDetails.spinobjectRequired ifConfigurations to generate a 360-spin of the vehicle. Required when media.spin is true. If it is missing, that output is skipped and the response is a 206 with error code "VAL_CONFIG_004". Send an empty object to use the defaults.
processingDetails.spin.hotspotbooleanOptionalSet to "true" to detect and include interactive hotspots on the spin. Defaults to false when omitted. Default: false.
processingDetails.spin.spinFrameCountstring (one of: 36, 72)OptionalNumber of frames to be used in the 360° spin generation. The accepted values are "36" or "72". Default: 36.
processingDetails.featureVideoobjectRequired ifConfigurations to generate a feature Video. Required when media.featureVideo is true. If it is missing, that output is skipped and the response is a 206 with error code "VAL_CONFIG_004". Send an empty object to use the defaults.
processingDetails.featureVideo.templateIdstringOptionalIdentifier for the video template used to generate the feature video. This ID is provided by the Spyne team; there is no default.
processingDetails.featureVideo.musicIdstringOptionalIdentifier for the background music to include in the video. This ID is provided by the Spyne team; there is no default.
processingDetails.featureVideo.voiceIdstringOptionalIdentifier for the voice-over added to the video. This ID is provided by the Spyne team; there is no default.
processingDetails.featureVideo.languagestringOptionalLanguage used for the generated voice-over script. Defaults to "english" when omitted. Default: english.
processingDetails.featureVideo.targetLanguagestringOptionalOutput language code for the voice-over. Defaults to "en" when omitted. Default: en.
processingDetails.featureVideo.fontobjectOptionalFont used for on-screen text, with "text" and "key" properties. Defaults to Montserrat for both when omitted.
processingDetails.featureVideo.font.textstringOptionalExample: Montserrat.
processingDetails.featureVideo.font.keystringOptionalExample: Montserrat.
processingDetails.featureVideo.themeColorsobjectOptionalTheme colours applied to the video, with a "primaryColor" property. Defaults to "#ffca13" when omitted.
processingDetails.featureVideo.themeColors.primaryColorstringOptionalExample: #ffca13.
dealerIdstringOptionalDeprecated and ignored. This field is accepted for backward compatibility but has no effect on processing. The team the vehicle is processed under is always taken from the authenticated API credential, not from this value.
vinMetaDataobjectOptionalFree-form vehicle attributes such as make, model, year, engine, interior and exterior details. Stored against the vehicle record and not interpreted by processing.
clientMetaDataobjectOptionalOpaque request-level metadata. Stored against the record and echoed back on Retrieve Media. Spyne does not interpret these keys.
mediaKitConfigobjectOptionalMedia kit overrides. "Note": supplying "banner" or "billboard" is rejected with 400 if the enterprise and team have a smart campaign in ACTIVE, PAUSED or SCHEDULED state, because a live campaign would override the media kit sent here.
mediaKitConfig.bannerobjectOptional
mediaKitConfig.billboardobjectOptional

Sample request

curl --request POST \
  --url 'https://api.spyne.ai/api/pv1/merchandise/process' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "vin": "1HGCM82633A004352",
  "vinMetaData": {
    "make": "Honda",
    "model": "Accord",
    "year": "2020"
  },
  "clientMetaData": {
    "dmsRef": "RO-88213"
  },
  "media": {
    "image": true,
    "spin": true
  },
  "mediaInput": {
    "imageData": [
      {
        "url": "https://cdn.example.com/veh/front.jpg",
        "clientMetaData": {
          "position": "front"
        }
      },
      {
        "url": "https://cdn.example.com/veh/rear.jpg"
      }
    ]
  },
  "processingDetails": {
    "backgroundId": "75282",
    "numberPlateLogo": "1",
    "image": {
      "catalogCount": 12
    },
    "spin": {
      "hotspot": true,
      "spinFrameCount": "36"
    }
  }
}'
import requests

url = "https://api.spyne.ai/api/pv1/merchandise/process"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
payload = {
    "vin": "1HGCM82633A004352",
    "vinMetaData": {
        "make": "Honda",
        "model": "Accord",
        "year": "2020"
    },
    "clientMetaData": {
        "dmsRef": "RO-88213"
    },
    "media": {
        "image": True,
        "spin": True
    },
    "mediaInput": {
        "imageData": [
            {
                "url": "https://cdn.example.com/veh/front.jpg",
                "clientMetaData": {
                    "position": "front"
                }
            },
            {
                "url": "https://cdn.example.com/veh/rear.jpg"
            }
        ]
    },
    "processingDetails": {
        "backgroundId": "75282",
        "numberPlateLogo": "1",
        "image": {
            "catalogCount": 12
        },
        "spin": {
            "hotspot": True,
            "spinFrameCount": "36"
        }
    }
}

response = requests.post(url, headers=headers, json=payload)
print(response.status_code, response.json())
const response = await fetch("https://api.spyne.ai/api/pv1/merchandise/process", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "vin": "1HGCM82633A004352",
    "vinMetaData": {
      "make": "Honda",
      "model": "Accord",
      "year": "2020"
    },
    "clientMetaData": {
      "dmsRef": "RO-88213"
    },
    "media": {
      "image": true,
      "spin": true
    },
    "mediaInput": {
      "imageData": [
        {
          "url": "https://cdn.example.com/veh/front.jpg",
          "clientMetaData": {
            "position": "front"
          }
        },
        {
          "url": "https://cdn.example.com/veh/rear.jpg"
        }
      ]
    },
    "processingDetails": {
      "backgroundId": "75282",
      "numberPlateLogo": "1",
      "image": {
        "catalogCount": 12
      },
      "spin": {
        "hotspot": true,
        "spinFrameCount": "36"
      }
    }
  }),
});
console.log(response.status, await response.json());

Sample response

{
  "success": true,
  "statusCode": 202,
  "message": "Processing initiated successfully",
  "data": {
    "vin": "1HGCM82633A004352",
    "stockNumber": "STK-4471",
    "dealerVinID": "fe89aa8d-5419-41f0-99bb-1e6e45691dcb",
    "source": "API",
    "dealerId": "86fc402add"
  }
}
{
  "success": true,
  "statusCode": 206,
  "message": "Request initiated with partial success",
  "data": {
    "stockNumber": "STK-4471",
    "dealerVinID": "fe89aa8d-5419-41f0-99bb-1e6e45691dcb",
    "source": "API",
    "dealerId": "86fc402add",
    "validationSummary": {
      "isRequestRejected": true,
      "displayError": {
        "code": "VAL_CONFIG_001",
        "message": "BackgroundId should not be null or empty",
        "product": null
      }
    }
  }
}
{
  "success": false,
  "statusCode": 400,
  "message": "At least one idenytifier (VIN, stockId, or registrationNumber) is required",
  "error": "Bad request"
}
{
  "success": false,
  "statusCode": 400,
  "message": "Received invalid urls, URLS:[not-a-url]",
  "error": "Bad request"
}
{
  "success": false,
  "statusCode": 400,
  "message": "Received inaccessible urls, URLS:[https://cdn.example.com/missing.jpg]",
  "error": "Bad request"
}
{
  "success": false,
  "statusCode": 400,
  "message": "More than 200 urls is not allowed. Received 201 urls.",
  "error": "Bad request"
}
{
  "success": false,
  "statusCode": 400,
  "message": "Processing with custom media kit (banner/billboard) is not allowed when an active/paused/scheduled smart campaign exists for this enterprise and team. Please deactivate the campaign before processing with a custom media kit.",
  "error": "Bad request"
}
{
  "code": "E_MISSING_OR_INVALID_PARAMS",
  "problems": [
    "\"mediaInput\" is required, but it was not defined."
  ],
  "message": "The server could not fulfill this request (`POST /api/pv1/merchandise/process`) due to 1 missing or invalid parameters."
}
{
  "status": "401",
  "message": "Invalid Auth key"
}
{
  "success": false,
  "statusCode": 500,
  "message": "Failed to process media request",
  "error": "Unknown error occurred"
}
{
  "success": false,
  "statusCode": 500,
  "message": "Failed to validate active campaigns",
  "error": "Internal server error"
}

Response parameters (202)

202 Accepted means the request passed validation and Spyne has started processing the vehicle. This is the only success status the endpoint returns. Processing is asynchronous, so no images, spin or video are ready yet: store the dealerVinID and use it to fetch the outputs once they are done. Identifier fields you did not send are left out of the response, not returned as null.

FieldTypeDescription
successbooleanAlways true for a 202.
statusCodeintegerAlways 202, matching the HTTP status.
messagestringAlways Processing initiated successfully.
dataobjectThe vehicle record Spyne created for this request.
data.vinstringThe VIN you sent. Omitted if the request had no VIN. Example: 1HGCM82633A004352.
data.stockNumberstringThe stock number you sent. Omitted if not sent. Example: STK-4471.
data.registrationNumberstringThe registration number you sent. Omitted if not sent. Example: KA01AB1234.
data.dealerVinIDstringSpyne's ID for this vehicle. Pass it as the dealerVinId query parameter of Retrieve a vehicle to fetch the outputs. Example: fe89aa8d-5419-41f0-99bb-1e6e45691dcb.
data.sourcestringAlways API for requests made through this endpoint.
data.dealerIdstringTeam the record was attributed to, taken from the credential. Example: 86fc402add.

Response parameters (206)

206 Partial Content means Spyne created the vehicle record and returned a dealerVinID, but the processing service rejected the processing request, typically because a required setting is missing or invalid. success is still true, so check statusCode or data.validationSummary rather than success alone. Read data.validationSummary.displayError to see what was rejected, correct the request and send it again.

FieldTypeDescription
successbooleantrue: the vehicle record was created even though processing was rejected.
statusCodeintegerAlways 206, matching the HTTP status.
messagestringSummary from the processing service when it provides one; otherwise Request initiated with partial success.
dataobjectThe vehicle record, plus the reason processing was rejected.
data.vinstringThe VIN you sent. Omitted if not sent.
data.stockNumberstringThe stock number you sent. Omitted if not sent.
data.registrationNumberstringThe registration number you sent. Omitted if not sent.
data.dealerVinIDstringSpyne's ID for the vehicle record that was created. Example: fe89aa8d-5419-41f0-99bb-1e6e45691dcb.
data.sourcestringAlways API.
data.dealerIdstringTeam the record was attributed to, taken from the credential. Example: 86fc402add.
data.validationSummaryobjectWhy the processing request was rejected. Its fields are listed below by name, relative to data.validationSummary.
isRequestRejectedbooleanAlways true in a 206.
displayErrorobjectThe error to fix before resending.
displayError.codestringMachine-readable error code. Example: VAL_CONFIG_001, returned when processingDetails.backgroundId is missing.
displayError.messagestringHuman-readable explanation of the error. Example: BackgroundId should not be null or empty.
displayError.productstring or nullThe output the error applies to, when the processing service names one; otherwise null.

Errors

StatusMeaningWhen it happens
400Bad RequestNo vehicle identifier supplied; an image URL was malformed, unreachable, or over the 200-URL limit; a custom media kit was sent while a live campaign exists; or any 4xx relayed from the processing service.
401UnauthorizedMissing or invalid credential. Emitted by the auth layer, and shaped differently to the other errors.
403ForbiddenReturned by the edge layer for a permission failure. The application itself collapses upstream 4xx into 400.
429Too Many RequestsReturned by the edge layer when a rate limit is exceeded. The application itself collapses upstream 4xx into 400.
500Internal Server ErrorProcessing service unreachable, or the campaign check failed.
503Service UnavailableReturned by the edge layer when the service is unavailable.

What happens next

  1. Store the dealerVinId. It is returned as soon as the request is accepted.
  2. Get the results. Poll Retrieve a vehicle, or receive them on your webhook.
  3. Check both statuses. Publish once aiStatus is DONE and qcStatus is qc_done.

Did this page help you?