Running shotstack api through backend via axios?

Hi guys,

Im having a little trouble trying to run shotstack render api endpoint on my backend server.

Currently using express/postgres.

router.get('/render',  async (req, res) => {
    try{
    const shotstack = await axios.post('https://api.shotstack.io/v1/render', {
    
        body: JSON.stringify(data),

        headers: {
            'Content-Type': 'application.json',
            'x-api-key': process.env.apikey,
            'accept': 'application/json'
        }
    })

    const response = await shotstack.json()
    res.status(200).send(response)
    // console.log(response)
    
}catch(err) {
    console.log(err)
    res.status(400).send(err)
}

})

I get returned a 403/404 error I can post the error json that i receive if that is helpful.

Thanks

Hey @chopstickboy,

The endpoint appears to be right. One explanation may be is when you use the wrong API key. Are you using the production key instead of the staging key for this particular request?

Also noticed you’re using application.json for the Content-Type header. That should be application/json

An alternative is to use the Node.js SDK, you can get a quick overview here: Node.js Video Editor - Shotstack.

This will take care of headers, API keys, etc… and also provides a collection of setter classes which can make working with the API a bit cleaner.

Hey all,

Would it have something to do with my “data” its currently formatted as a variable as an object following json format.

var data = {
…data
}

ill try using the sdk and see if that makes any difference. As for the API KEY im currently using my staging key with the stage endpoint. so i dont think that is the case.

UPDATE:

Thanks @lucas.spielberg, the sdk works and fixes the issue i was having. I am still not sure what was causing it.

@dazzatron my API key is for staging i was testing it on both staging and v1 incase it was wrong. they both produced the error message below. Also thank you for catching the application.json i fixed that and still also continued with a 400

I think it would be good to try and resolve the issue using axios.post() if possible. Ill post my template.js file and the error message:

const data = {
    "timeline": {
      "soundtrack": {
        "src": "https://shotstack-assets.s3-ap-southeast-2.amazonaws.com/music/freepd/motions.mp3",
        "effect": "fadeOut"
      },
      "background": "#000000",
      "tracks": [
        {
          "clips": [
            {
              "asset": {
                "type": "image",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/images/AROSS+Brand+logo+Intro.jpg"
              },
              "start": 0,
              "length": 15,
              "position": "bottomLeft",
              "scale": 0.25,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "image",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/images/AROSS+Brand+logo+Intro.jpg"
              },
              "start": 21,
              "length": 2,
              "position": "bottomLeft",
              "scale": 0.25,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "image",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/images/aross_Picture1+copy.jpg"
              },
              "start": 0,
              "length": 1,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "Alex Ross",
                "style": "vogue",
                "position": "center",
                "size": "medium"
              },
              "start": 1,
              "length": 1,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 2,
              "length": 2,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "executive",
                "style": "blockbuster",
                "position": "topRight",
                "size": "medium"
              },
              "start": 4,
              "length": 2,
              "transition": {
                "in": "carouselLeft"
              },
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 4,
              "length": 2,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "image",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/images/aross_Picture1+copy.jpg"
              },
              "start": 6,
              "length": 1,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 7,
              "length": 2,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 9,
              "length": 2,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "interviewer",
                "style": "blockbuster",
                "position": "topRight",
                "size": "medium"
              },
              "start": 11,
              "length": 4,
              "transition": {
                "in": "carouselLeft"
              },
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 11,
              "fit": "contain",
              "length": 2
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 13,
              "length": 2,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "exPAT",
                "style": "blockbuster",
                "position": "center",
                "size": "medium"
              },
              "start": 15,
              "length": 2,
              "transition": {
                "in": "fade"
              },
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "conNECTOR",
                "style": "blockbuster",
                "position": "center",
                "size": "medium"
              },
              "start": 17,
              "length": 1
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "interNATIONALIST",
                "style": "blockbuster",
                "position": "center",
                "size": "medium"
              },
              "start": 18,
              "length": 1,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "powerboat ENTHUSIAST",
                "style": "blockbuster",
                "position": "center",
                "size": "medium"
              },
              "start": 19,
              "length": 1,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "entREPRENEUR",
                "style": "blockbuster",
                "position": "center",
                "size": "medium"
              },
              "start": 20,
              "length": 1,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 15,
              "fit": "contain",
              "length": 6,
              "scale": 0.5,
              "offset": {
                "x": -0.25,
                "y": -0.25
              },
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 16,
              "fit": "contain",
              "length": 5,
              "scale": 0.5,
              "offset": {
                "x": 0.25,
                "y": -0.25
              },
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 17,
              "fit": "contain",
              "length": 4,
              "scale": 0.5,
              "offset": {
                "x": 0.25,
                "y": 0.25
              },
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 18,
              "length": 3,
              "scale": 0.5,
              "offset": {
                "x": -0.25,
                "y": 0.25
              },
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "video",
                "src": "https://frostcm-images-and-videos.s3.us-east-2.amazonaws.com/videoClips/Time+Sqaure+1+(1).MOV"
              },
              "start": 21,
              "length": 2,
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "Alex Ross",
                "style": "blockbuster",
                "position": "center",
                "size": "medium"
              },
              "start": 23,
              "length": 2,
              "transition": {
                "in": "fade"
              },
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "Personal Brand Video",
                "style": "subtitle",
                "position": "bottom",
                "size": "medium"
              },
              "start": 23,
              "length": 2,
              "transition": {
                "in": "fade"
              },
              "fit": "contain"
            }
          ]
        },
        {
          "clips": [
            {
              "asset": {
                "type": "title",
                "text": "Frost Cool Media",
                "style": "vogue",
                "position": "center",
                "size": "medium"
              },
              "start": 25,
              "length": 5,
              "transition": {
                "in": "fade"
              },
              "fit": "contain"
            }
          ]
        }
      ]
    },
    "output": {
      "format": "mp4",
      "resolution": "sd",
      "aspectRatio": "9:16"
    },
    // "callback": "localhost:8080/api/shotstack/render"

  }
  
  module.exports = data

ERROR:

Error: Request failed with status code 403
    at createError (C:\Users\ngjus\Desktop\Coding\lambdaNode\node_modules\axios\lib\core\createError.js:16:15)
    at settle (C:\Users\ngjus\Desktop\Coding\lambdaNode\node_modules\axios\lib\core\settle.js:17:12)
    at IncomingMessage.handleStreamEnd (C:\Users\ngjus\Desktop\Coding\lambdaNode\node_modules\axios\lib\adapters\http.js:293:11)
    at IncomingMessage.emit (events.js:412:35)
    at IncomingMessage.emit (domain.js:470:12)
    at endReadableNT (internal/streams/readable.js:1317:12)
    at processTicksAndRejections (internal/process/task_queues.js:82:21)

then there is an extremely long console log for the returned object.

There’s a few trailing comma’s in your JSON. JS supports trailing comma’s but JSON does not. I removed the trailing comma’s and the render went through ok.

Ah okay, I copied and pasted the template from a coworker. Thanks for catching that and clarifying.

Did it fix the problems for you?

A useful tool I often use for JSON validation is https://jsonlint.com/

I wanted to check what was going on with your axios request, dig a little deeper, as it should work. I checked the docs and if you use the post method then you need to use the following signature:

axios.post(url[, data[, config]])

See here: GitHub - axios/axios: Promise based HTTP client for the browser and node.js

Your code from above has a combination of data and config rolled in to one which won’t work. You get a 403 because the headers are not being received at our end.

const shotstack = await axios.post('https://api.shotstack.io/v1/render', {
    body: JSON.stringify(data),

    headers: {
        'Content-Type': 'application.json',
        'x-api-key': process.env.apikey,
        'accept': 'application/json'
    }
})

The correct way to do this would be:

const shotstack = await axios.post('https://api.shotstack.io/v1/render', data, {
    headers: {
        'Content-Type': 'application/json',
        'x-api-key': process.env.apikey,
    }
})

This now matches the signature post(url, data, config), data can be sent as is and doesn’t need to be stringified.

Hope this helps if you decide to go back to Axios.

When I tried it your way, i am receiving a different error.

ypeError: Converting circular structure to JSON
→ starting at object with constructor ‘ClientRequest’
| property ‘socket’ → object with constructor ‘TLSSocket’
— property ‘_httpMessage’ closes the circle
at JSON.stringify ()
at stringify (C:\Users\ngjus\Desktop\Coding\lambdaNode\node_modules\express\lib\response.js:1123:12)
at ServerResponse.json (C:\Users\ngjus\Desktop\Coding\lambdaNode\node_modules\express\lib\response.js:260:14)
at ServerResponse.send (C:\Users\ngjus\Desktop\Coding\lambdaNode\node_modules\express\lib\response.js:158:21)
at C:\Users\ngjus\Desktop\Coding\lambdaNode\routes\api\shotStack.js:20:21
at processTicksAndRejections (internal/process/task_queues.js:95:5)

I am unsure what was causing this. I removed the trailing commas in the template.js file.

That or if i use {body: JSON.stringify(data)} i get a 400 error.

Can you share your latest code?

router.get('/render', async (req, res) => {
    try {
        const shotstack = await axios.post('https://api.shotstack.io/stage/render', {body: data}, {
            headers: {
                'Content-Type': 'application/json',
                'x-api-key': process.env.SSAPIKEYSTAGE
            }
        })

        console.log(shotstack)
    } catch (error) {
        console.log(error)
    }
    })

That is my current code. I used the website you linked to check if it was valid json, so i know there shouldnt be anymore errors with the template file.

This should just be data. There is no need to add body