API Reference v2

Jobs API

Create a job

Endpoint: POST /v2/jobs

curl https://api.coconut.co/v2/jobs \
-u your-api-key: \
-d '{
  "input": {
    "url": "https://s3.amazonaws.com/bucket/file.avi"
  },
  "storage": {
    "service": "s3",
    "region": "us-east-1",
    "bucket": "mybucket",
    "credentials": {
      "access_key_id": "...",
      "secret_access_key": "..."
    }
  },
  "notification": {
    "type": "http",
    "url": "http://site.com/webhook"
  },
  "outputs": {
    "mp4:720p": {
      "path": "/720p/video.mp4"
    },
    "mp4:1080p": {
      "path": "/1080p/video.mp4"
    },
    "httpstream": {
      "hls": {
        "path": "/hls"
      },
      "dash": {
        "path": "/dash",
        "hlsfmp4": true
      }
    }
  }
}'


Parameters

NameTypeDefaultRequired
settings
The job settings. See Settings.
hash No
input
The input file URL. See Input.
hash Yes
storage
The storage service where all the outputs will be uploaded. See Storage.
hash Yes
outputs
The outputs. See Outputs.
hash Yes
notification
The notification settings to get notified when the job is completed. See Notification.
hash Yes

Response examples

When the job is successfully submitted:

HTTP/1.1 201 Created
Server: nginx/1.4.6 (Ubuntu)
Date: Wed, 08 Oct 2014 10:25:55 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: close

{
  "id": "vdq1fShawHzyz3",
  "created_at": "2021-02-15 14:39:46 +0100",
  "completed_at": null,
  "status": "job.starting",
  "progress": "0%",
  "input": {
    "status": "input.starting"
  },
  "outputs": [
    {
      "key": "mp4:240p",
      "type": "video",
      "format": "mp4:240p",
      "status": "video.waiting"
    }
  ]
}


If there is an error with the request:

HTTP/1.1 400 Bad Request
Server: nginx/1.4.6 (Ubuntu)
Date: Wed, 08 Oct 2014 14:17:27 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: close

{
  "message":"The storage credentials are not correct, you must define your 'access_key_id' and 'secret_access_key'.",
  "error_code":"storage_credentials_not_valid",
  "status":"error"
}


You can find the list of error codes here.

Getting information about a job

Endpoint: GET /v2/jobs/:jobid

curl https://api.coconut.co/v2/jobs/zfO55hr7AfAsld -u your-api-key:

{
  "id": "zfO55hr7AfAsld",
  "created_at": "2021-02-15 13:43:42 +0000",
  "completed_at": "2021-02-15 13:46:34 +0000",
  "status": "job.completed",
  "progress": "100%",
  "input": {
    "status": "input.transferred"
  },
  "outputs": [
    {
      "key": "mp4",
      "type": "video",
      "format": "mp4",
      "url": "http://cdn.coconut.co/test.mp4",
      "status": "video.encoded"
    },
    {
      "key": "httpstream",
      "type": "httpstream",
      "format": "httpstream",
      "urls": [
        {
          "format": "dash",
          "url": "http://cdn.coconut.co/dash/master.mpd"
        },
        {
          "format": "hls",
          "url": "http://cdn.coconut.co/hls/master.m3u8"
        }
      ],
      "status": "httpstream.packaged"
    },
    {
      "key": "jpg:320x",
      "type": "image",
      "format": "jpg:320x",
      "urls": [
        "http://cdn.coconut.co/jpg/thumbs_01.jpg",
        "http://cdn.coconut.co/jpg/thumbs_02.jpg",
        "http://cdn.coconut.co/jpg/thumbs_03.jpg",
        "http://cdn.coconut.co/jpg/thumbs_04.jpg",
        "http://cdn.coconut.co/jpg/thumbs_05.jpg",
        "http://cdn.coconut.co/jpg/thumbs_06.jpg",
        "http://cdn.coconut.co/jpg/thumbs_07.jpg"
      ],
      "status": "image.created"
    }
  ]
}


Job status

Here are the list of status you can see:

StatusDescription
job.starting The job has just been created and will start now.
job.completed The job is completed and successful.
job.failed The job is completed but contains at least one failed process.
input.starting We just started the job and the input file is about to be transferred to Coconut.
input.transferring The input file is transferring to Coconut.
input.transferred The input file is transferred to Coconut, ready for processing all the outputs.
input.failed The input file hasn't been transferred properly because of URL returning an error, or broken media file.
video.waiting The output process is not enqueued yet for processing. The input file is still transferring.
video.queued The output process is queued for processing and should start.
video.encoding The video is encoding.
video.encoded The video has been encoded and uploaded successfully.
video.failed We encounter an FFmpeg error while converting the input file.
video.skipped The output video has been skipped because of the output condition returned false.
image.waiting The output process is not enqueued yet for processing. The input file is still transferring.
image.queued The output process is queued for processing and should start.
image.processing The images are being genetated.
image.created The images has been created and uploaded successfully.
image.failed We got an error while generating the images or we couldn't upload them to your storage.
image.skipped The output image has been skipped because of the output condition returned false.
httpstream.waiting The output process is not enqueued yet for processing. The input file is still transferring.
httpstream.queued The output process is queued for processing and should start.
httpstream.variants.encoding We are encoding the input file into multiple variants.
httpstream.packaging We are currently packaging into HLS/Dash.
httpstream.packaged The playlist (m3u8, mpd) and media files have been generated and uploaded successfully.
httpstream.failed We got an error while packaging or we couldn't upload the media files to your storage.
httpstream.skipped The output image has been skipped because of the output condition returned false.

Conditional outputs

By using if, you can choose if an output needs to be processed or not according to a condition. If the condition returns false, then the output will be skipped.

Prevent upscaling

You won't want to convert a 720p video to 4k output, that would be a waste of time, space and money. So to avoid that, we've created those conditional outputs to help you:

{
  "outputs": {
    "mp4:360p::quality=4": {
      "key": "mp4:360p",
      "path": "/mp4/360p/video.mp4",
      "if": "{{ input.width }} >= 480"
    },
    "mp4:480p::quality=4": {
      "key": "mp4:480p",
      "path": "/mp4/480p/video.mp4",
      "if": "{{ input.width }} >= 720"
    },
    "mp4:720p::quality=4": {
      "key": "mp4:720p",
      "path": "/mp4/720p/video.mp4",
      "if": "{{ input.width }} >= 1280"
    },
    "mp4:1080p::quality=4": {
      "key": "mp4:1080p",
      "path": "/mp4/1080p/video.mp4",
      "if": "{{ input.width }} >= 1920"
    },
    "mp4:2160p::quality=4": {
      "key": "mp4:2160p",
      "path": "/mp4/2160p/video.mp4",
      "if": "{{ input.width }} >= 3840"
    }
  }
}



Detecting portrait or landscape videos

Sometimes you want to use different resolution depending on the orientation. Here is an example for both portrait and landscape which takes into account the rotation metadata + source resolution:

{
  "outputs": {
    "mp4:x1024::quality=3": {
      "key": "mp4"
      "path": "video.mp4",
      "if": "({{ input.rotation }} = 0 or {{ input.rotation }} = 180) and {{ input.width }} > {{ input.height }}"
    },
    "mp4:1024x::quality=3": {
      "key": "mp4"
      "path": "video.mp4",
      "if": "(({{ input.rotation }} = 90 or {{ input.rotation }} = 270) and {{ input.width }} > {{ input.height }}) or {{ input.height }} > {{ input.width }}"
    }
  }
}


Same output format with different settings

There are many reasons why you would want to create multiple outputs with the same format but different settings, like generating regular thumbnails and squared ones with the same resolution, or even creating a trailer by cutting the output.

Here is an example:

{
  "outputs": {
    "mp4:::quality=4": [
      {
        "key": "mp4:trailer",
        "path": "trailer.mp4",
        "duration": 60
      },
      {
        "key": "mp4",
        "path": "video.mp4"
      }
    ],
    "jpg:400x": [
      {
        "key": "jpg:reg",
        "path": "thumb_%.2d.jpg",
        "number": 10
      },
      {
        "key": "jpg:sq",
        "path": "thumb_sq_%.2d.jpg",
        "number": 4,
        "square": true
      }
    ]
  }
}


Note that if you don't provide a key, it will be generated for you following this rule: format:index.

Ultrafast Mode

If enable, the input video is split into small chunks that are transcoded in parallel over multiple servers. The speed is greatly increased, for instance, you can expect x5 speed for 4k outputs.

We advise to use the Ultrafast mode in the following cases:

  • If your videos are longer than 10 minutes
  • Your job includes 1080p and 4k outputs
  • Any HEVC transcoding

Note that ultrasfast only works for videos longer than a minute.

curl https://api.coconut.co/v2/jobs \
-u your-api-key: \
-d '
{
  "settings": {
    "ultrafast": true
  },
  "input": {
    "url": "https://s3.amazonaws.com/bucket/4k.mp4"
  },
  "storage": {
    "service": "s3",
    "region": "us-east-1",
    "bucket": "mybucket",
    "credentials": {
      "access_key_id": "...",
      "secret_access_key": "..."
    }
  },
  "notification": {
    "type": "http",
    "url": "http://site.com/webhook"
  },
  "outputs": {
    "mp4:hevc_2160p": {
      "path": "/4k/video.mp4"
    },
    "mp4:hevc_1080p": {
      "path": "/1080p/video.mp4"
    }
  }
}'

Built-in variables

Here are the built-in variables usable in the job request:

VariableTypeDescription
input.mime_typestring
input.file_sizeintsize in bytes
input.formatstring
input.widthint
input.heightint
input.fpsfloat
input.ifpsint
input.video_bitrateintbitrate in kbps
input.rotationintrotation in degrees. 0 if video is not rotated.
input.is_hdbooltrue if at least 720p
input.is_audio_onlybooltrue if audio only
input.durationintduration in second
input.video_codecstring
input.audio_codecstring
input.channelsint2 for stereo, 1 for mono, 0 for no audio
input.audio_bitrateintbitrate in kbps
input.sample_rateintsample rate in Hz