API Reference

This document describes the API of tinypng.com and tinyjpg.com. The API is a public HTTP service that returns JSON. This document assumes you are familiar with performing HTTP requests and parsing JSON responses.

The API is hosted at api.tinify.com and can handle both JPEG and PNG files. It will detect the image by its content and return the media type of the original and compressed image.

Example usage

To shrink a PNG or JPEG image, post the data to the API service. The response is a JSON message. The initial request must be authorized with HTTP Basic authorization.

Example request

POST /shrink HTTP/1.1
Host: api.tinify.com
Authorization: Basic YXBpOmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1

The post data should contain the image binary. The Authorization header should contain a Base64 digest of the string api:KEY, where KEY is the API key that has been provided to you. You can obtain a free key by registering with your name and email address.

For example, if you have a file named test.png in the current directory and your API key is ABC123:

curl -i --user api:ABC123 --data-binary @test.png https://api.tinify.com/shrink

Example response when successful

HTTP/1.1 201 Created
Compression-Count: 1
Location: https://api.tinify.com/output/2xnsp7jn34e5.png
Content-Type: application/json; charset=utf-8

{
  "input": {
    "size": 207565,
    "type": "image/png"
  },
  "output": {
    "size": 63669,
    "type": "image/png",
    "ratio": 0.307
  }
}

Example response when unsuccessful

HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json; charset=utf-8

{
  "error": "BadSignature",
  "message": "Does not appear to be a PNG or JPEG file"
}

Reference

Currently there is only one endpoint. This section describes the possible responses.

Response when successful

If the HTTP status code is 201, the image was successfully compressed. Use the Location header to retrieve the compressed file. The structure of the URL may change in the future, so make sure to use it verbatim. The output will be available for at least one hour, after which it is automatically deleted.

The response body is encoded as JSON and contains the following additional information:

input.size
The size in bytes of the original image file.
input.type
The media type of the original image file: image/png or image/jpeg.
output.size
The size in bytes of the compressed output.
output.ratio
The output size divided by the input size.
output.type
The media type of the compressed file: image/png or image/jpeg. The input and output types are currently always the same, but this may change in the future. If it changes we will consider this a breaking change and provide a migration path for all users.
output.url (deprecated)
URL that points to the compressed file. Please use the Location header instead.

The usage of the current month is available in the custom Compression-Count header.

Response when unsuccessful

If the status code is in the 400 range, the request could not be fulfilled because of a problem with the submitted data. If the HTTP status code is in the 500 range, compression is temporarily be unavailable. The JSON response will always contain a brief explanation of the reason.

error
Identifier of the error cause, see below for details.
message
A brief explanation of the error.

List of errors

The following errors may be returned. This list may be expanded in the future.

Unauthorized
The request was not authorized with a valid API key.
InputMissing
The file that was uploaded is empty or no data was posted.
BadSignature
The file was not recognized as a PNG or JPEG file. It may be corrupted or it is a different file type.
UnsupportedFile
The file was recognized as a PNG or JPEG file, but is not supported. Currently we do not support JPEG files in CMYK color space. Note that images in this color space are also not supported in IE 8 and earlier.
DecodeError
The file had a valid PNG or JPEG signature, but could not be decoded. It may be corrupted or is of an unsupported type. If you are positive you are sending a correct file, feel free to contact us and send the file to us for diagnostics.
TooManyRequests
Your monthly upload limit has been exceeded. Either wait until the next calendar month, or upgrade your subscription.
InternalServerError
An internal error occurred during compression. This error is usually temporary. If the uploaded file is a valid PNG or JPEG file, you can try again later.

Code samples

We've created some examples that demonstrate how you can use the API in a few programming language. Want to contribute example code in your favourite language? Let us know!

Node.js

var https = require("https");
var fs = require("fs");

var key = "<your api key>";
var input = fs.createReadStream("large-input.png");
var output = fs.createWriteStream("tiny-output.png");

/* Uncomment below if you have trouble validating our SSL certificate.
   Download cacert.pem from: http://curl.haxx.se/ca/cacert.pem */
// var boundaries = /-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----\n/g
// var certs = fs.readFileSync(__dirname + "/cacert.pem").toString()
// https.globalAgent.options.ca = certs.match(boundaries);

var options = require("url").parse("https://api.tinify.com/shrink");
options.auth = "api:" + key;
options.method = "POST";

var request = https.request(options, function(response) {
  if (response.statusCode === 201) {
    /* Compression was successful, retrieve output from Location header. */
    https.get(response.headers.location, function(response) {
      response.pipe(output);
    });
  } else {
    /* Something went wrong! You can parse the JSON body for details. */
    console.log("Compression failed");
  }
});

input.pipe(request);

PHP with fopen

$key = "<your api key>";
$input = "large-input.png";
$output = "tiny-output.png";

$url = "https://api.tinify.com/shrink";
$options = array(
  "http" => array(
    "method" => "POST",
    "header" => array(
      "Content-type: image/png",
      "Authorization: Basic " . base64_encode("api:$key")
    ),
    "content" => file_get_contents($input)
  ),
  "ssl" => array(
    /* Uncomment below if you have trouble validating our SSL certificate.
       Download cacert.pem from: http://curl.haxx.se/ca/cacert.pem */
    // "cafile" => __DIR__ . "/cacert.pem",
    "verify_peer" => true
  )
);

$result = fopen($url, "r", false, stream_context_create($options));
if ($result) {
  /* Compression was successful, retrieve output from Location header. */
  foreach ($http_response_header as $header) {
    if (strtolower(substr($header, 0, 10)) === "location: ") {
      file_put_contents($output, fopen(substr($header, 10), "rb", false));
    }
  }
} else {
  /* Something went wrong! */
  print("Compression failed");
}

PHP with curl

$key = "<your api key>";
$input = "large-input.png";
$output = "tiny-output.png";

$request = curl_init();
curl_setopt_array($request, array(
  CURLOPT_URL => "https://api.tinify.com/shrink",
  CURLOPT_USERPWD => "api:" . $key,
  CURLOPT_POSTFIELDS => file_get_contents($input),
  CURLOPT_BINARYTRANSFER => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HEADER => true,
  /* Uncomment below if you have trouble validating our SSL certificate.
     Download cacert.pem from: http://curl.haxx.se/ca/cacert.pem */
  // CURLOPT_CAINFO => __DIR__ . "/cacert.pem",
  CURLOPT_SSL_VERIFYPEER => true
));

$response = curl_exec($request);
if (curl_getinfo($request, CURLINFO_HTTP_CODE) === 201) {
  /* Compression was successful, retrieve output from Location header. */
  $headers = substr($response, 0, curl_getinfo($request, CURLINFO_HEADER_SIZE));
  foreach (explode("\r\n", $headers) as $header) {
    if (strtolower(substr($header, 0, 10)) === "location: ") {
      $request = curl_init();
      curl_setopt_array($request, array(
        CURLOPT_URL => substr($header, 10),
        CURLOPT_RETURNTRANSFER => true,
        /* Uncomment below if you have trouble validating our SSL certificate. */
        // CURLOPT_CAINFO => __DIR__ . "/cacert.pem",
        CURLOPT_SSL_VERIFYPEER => true
      ));
      file_put_contents($output, curl_exec($request));
    }
  }
} else {
    print(curl_error($request));
  /* Something went wrong! */
  print("Compression failed");
}

Python 3

from os.path import dirname
from urllib.request import Request, urlopen
from base64 import b64encode

key = "<your api key>"
input = "large-input.png"
output = "tiny-output.png"

request = Request("https://api.tinify.com/shrink", open(input, "rb").read())

cafile = None
# Uncomment below if you have trouble validating our SSL certificate.
# Download cacert.pem from: http://curl.haxx.se/ca/cacert.pem
# cafile = dirname(__file__) + "/cacert.pem"

auth = b64encode(bytes("api:" + key, "ascii")).decode("ascii")
request.add_header("Authorization", "Basic %s" % auth)

response = urlopen(request, cafile = cafile)
if response.status == 201:
  # Compression was successful, retrieve output from Location header.
  result = urlopen(response.getheader("Location"), cafile = cafile).read()
  open(output, "wb").write(result)
else:
  # Something went wrong! You can parse the JSON body for details.
  print("Compression failed")

Ruby

require "net/https"
require "uri"

key = "<your api key>"
input = "large-input.png"
output = "tiny-output.png"

uri = URI.parse("https://api.tinify.com/shrink")

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

# Uncomment below if you have trouble validating our SSL certificate.
# Download cacert.pem from: http://curl.haxx.se/ca/cacert.pem
# http.ca_file = File.join(File.dirname(__FILE__), "cacert.pem")

request = Net::HTTP::Post.new(uri.request_uri)
request.basic_auth("api", key)

response = http.request(request, File.binread(input))
if response.code == "201"
  # Compression was successful, retrieve output from Location header.
  File.binwrite(output, http.get(response["location"]).body)
else
  # Something went wrong! You can parse the JSON body for details.
  puts "Compression failed"
end

C# with .NET

using System;
using System.Net;
using System.Text;
using System.IO;

class Program {
  static void Main() {
    string key = "<your api key>";
    string input = "large-input.png";
    string output = "tiny-output.png";

    string url = "https://api.tinify.com/shrink";

    WebClient client = new WebClient();
    string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes("api:" + key));
    client.Headers.Add(HttpRequestHeader.Authorization, "Basic " + auth);

    try {
      client.UploadData(url, File.ReadAllBytes(input));
      /* Compression was successful, retrieve output from Location header. */
      client.DownloadFile(client.ResponseHeaders["Location"], output);
    } catch (WebException) {
      /* Something went wrong! You can parse the JSON body for details. */
      Console.WriteLine("Compression failed.");
    }
  }
}

Java 7

You will need Java 7 Update 76 or newer to run this example out of the box. The GoDaddy G2 CA server is missing in the default Java keystore in older Java 7 versions. An alternative is to add the GoDaddy G2 CA server (http://certificates.godaddy.com/repository/gdig2.crt) manually to your Java keystore.

import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import javax.xml.bind.DatatypeConverter;

public class Program {
  private static final String API_URL = "https://api.tinify.com/shrink";

  public static void main(String[] args) throws Exception {
    final String key = "<your api key>";
    final String input = "large-input.png";
    final String output = "tiny-output.png";

    HttpURLConnection connection = (HttpURLConnection) new URL(API_URL).openConnection();
    String auth = DatatypeConverter.printBase64Binary(("api:" + key).getBytes("UTF-8"));
    connection.setRequestProperty("Authorization", "Basic " + auth);
    connection.setDoOutput(true);

    try (OutputStream request = connection.getOutputStream()) {
      Files.copy(Paths.get(input), request);
    }

    if (connection.getResponseCode() == 201) {
      // Compression was successful, retrieve output from Location header.
      final String url = connection.getHeaderFields().get("Location").get(0);
      connection = (HttpURLConnection) new URL(url).openConnection();
      try (InputStream response = connection.getInputStream()) {
        Files.copy(response, Paths.get(output), StandardCopyOption.REPLACE_EXISTING);
      }
    } else {
      // Something went wrong! You can parse the JSON body for details.
      System.out.println("Compression failed.");
    }
  }
}

Try TinyPNG with a new browser

TinyPNG is created for modern browers with HTML5 & CSS3 support. We have not tried it out in other browsers. The site may work, or it may not. If you see this message you may want to try a different browser!