PDFShift API Documentation (v3.0)

Introduction

Welcome to the PDFShift API. This documentation contains all the details needed to use the API and how to convert documents from HTML to PDF.

You will find code samples in Shell, Javascript, Python and PHP.

Authentication

Authenticate your account by including your secret key in API requests.
You can manage your API keys in the Dashboard.

Authentication to the API is performed via HTTP Basic Auth.

In order to connect, provide the basic auth values with "api" as the username, and your API Key as the password.

Note that the username value is ignored on PDFShift.
We suggest to set to "api" to have some values, but anything will work as long as it's compatible with the standard.

Authorization: Basic api:your_api_key

Sandbox

We highly recommend you to set the sandbox parameter to true when starting with PDFShift, and in development mode.

When enabled, the sandbox parameter adds a watermark to your generated PDF, but does not count the conversions made via PDFShift.

That way, you can set up your code and run multiple tests without worrying about your remaining credits.

Once all is set, you can run a last test locally with the sandbox removed or set to false to ensure the PDF renders exactly like you want.

Note In case you forgot to set the sandbox parameter to true while working on your code, don't worry. Simply reach out to us and we'll remove some of your credits usage for free during the first month :)

Rate Limit

Rate limiting is only forced for unauthenticated accounts with a limit of 2 requests per minutes.

Once authenticated, you can convert up to 250 documents per minute (10 only if you use the sandbox mode).

When reaching the rate limit, you will get an HTTP status code of 429.

Each request will contain three headers to let you know your usage:

Key Explanation
X-RateLimit-Remaining Indicates the number of requests before hitting the rate limit.
X-RateLimit-Reset Indicates the number of requests you can make per minutes (always 45).
X-RateLimit-Reset Indicates when the rate limit will reset.
# HTTP response from PDFShift's API will contain these three headers:

X-RateLimit-Remaining: 30
X-RateLimit-Limit: 45
X-RateLimit-Reset: 1466368960

Getting an API Key

In order to generate PDF without the PDFShift's watermark, you will need an API Key.
You can request one by creating an account on PDFShift's website.

Once you have submitted the form, we will send you an email containing your API Key.
You can also create other API Key if you want, to split your keys accross your project.
This can be done via your Dashboard.

You can test and play with our API without an API Key. Simply don't provide a "Basic Auth" header and the request will be done, with the difference that a watermark will be applied to the document.
Note that applying a watermark makes the generation slower, so you will have better result when using your API Key.

Errors

Most of the errors you will encounter when using our API can be found here. In case something is missing, feel free to let us know.

The PDFShift API uses the following error codes:

Error Code Meaning
400 Bad Request -- Your request is invalid. Often, it means a parameter was wrongly set.
401 Unauthorized -- No API key were found.
403 Forbidden -- The provided API key is invalid.
404 Not Found -- The page you tried to reach was not found.
405 Method Not Allowed -- The endpoint you tried to reach is not available with this HTTP method.
408 A timeout error occured when trying to convert a document.
429 Too Many Requests -- You sent too many request. Please see the Rate limiting section for more details.
500 Internal Server Error -- We had a problem with our server.

Support

If you need any help converting your HTML documents, feel free to reach out to our support team.

We are available via [email protected] and we will do our best to help you convert your documents the way you want to.

Convert

Converts an html document to pdf

Body parameter

String

Original document to convert to PDF. PDFShift will automatically detect if it's an URL and load it, or an HTML document and charge it.
You can also send an array of documents to convert if parallel conversions is enabled on your account. In that case, you will also need to provide the webhook parameters as this operation is asynchronous.

Boolean

Will generates documents that doesn't count in the credits. The generated document will come with a watermark and you are limited to 10 documents per minutes.

Boolean

Will return the generated PDF in Base64 encoded format, instead of raw.

String

Name of the destination file. Only an alphanumerical value with \"-\" or \"_\", of at least 7 chars accepted. If given, the response will not be the PDF, but a JSON response containing an url parameter to an Amazon S3 bucket, to download the file. The file will be kept for 2 days, then automatically deleted. See Saving the document to Amazon S3 for an example.

String

An URL where we will send a POST request containing a JSON body similar to when you use the filename parameter. The JSON response will contain a URL key that points to your file, stored on Amazon S3.

String

Path to your S3 bucket, in order to save the converted PDF directly into your AWS S3 account. See Saving to your Amazon S3 for more details. Use a full path value like s3://doc-example-bucket/pdfshift/upload/86aa3ede7d05.pdf.

Number

If provided, will kill the page loading at a specified time without stopping with a TimeoutError. Value in seconds.

String

Name of a function available globally. When present, PDFShift will wait for this function to return a truthy value (true, 1, a string, etc) or up to 30 seconds, then proceed to the conversion. If the function never returns a truthy value in the allocated time, the conversion will fail with an error.

Boolean

Will set the view in landscape mode instead of portrait.

String

Will append this CSS styles to the document before saving it. Can be an URL or a String of CSS rules.

String

Will execute the given Javascript before saving the document. Can be an URL or a String of JS code.

Boolean

Will not execute the javascript at all in the document.

Boolean

The final document will not have the background images.

Boolean

Remove the last page if it is considered empty.

Number

In milliseconds. Will wait for this duration before capturing the document. Up to 10 seconds max.

Boolean

Will stop the conversion if the status_code from the given source is not 2XX. Default is False

Boolean

Use the print stylesheet instead of the general one.

String

Format of the document. You can either use the standard values (Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5) or a custom {width}x{height} value. For {width} and {height}, you can indicate the following units: in, cm, mm.

String

Pages to print. Can be one number (3), a range (1-5), a list (4,5,6) or a combination of both (1-3,6,7). If the number is higher than the real number of pages, that number will be ignored.

Number

A value between 0 and 2. Allows you to increase the zoom in the document for specific purposes. 1 is the default zoom, lower is smaller, higher is bigger.

Object

Empty spaces between the outer and the beginning of the content. See the Margin section for more details.

String

Space between the top and the content.

String

Space between the right and the content.

String

Space between the bottom and the content.

String

Space between the left and the content.

Object

Object containing username and password for accessing password-protected content.

String

Username value from the Basic Authentication scheme.

String

Password value from the Basic Authentication scheme.

Array

List of cookies you want to send along with the requests when loading the source. They must be provided as an array of objects with the following properties:

String

Name of the cookie.

String

Value for the specified cookie.

Boolean

If set to true, This cookie will only be available for secure (https) connections.

Boolean

If set to true, this cookie will only be available to HTTP request only (no javascript).

Object

List of HTTP headers that you can pass to the request.

Object

Defines a custom header. See the Header/Footer section for more details.

String

Element to add in the header part of the document. You can use variables, indicated at the end of the document. PDFShift will automatically detect if it's an URL and load it, or an HTML data and charge it.

Accepted variables are:

Variable Description
{{date}} Formatted print date
{{title}} Title of the HTML document
{{url}} Page URL
{{page}} Current page
{{total}} Total number of pages

String

A spacing between the header and the content.

Object

Will add restrictions on the PDF document. See the Protection section for more details.

String

Document's author name.

String

A user who has the password will be able to view the document and perform operations allowed by the permission options.

String

A user who has the password will have unlimited access to the PDF, including changing the passwords and permission options.

Boolean

When set to true, printing will be disabled.

Boolean

When set to true, the possibility to copy any text will be disabled.

Boolean

When set to true, the possibility to modify the document will be disabled.

Object

Add a watermark to the generated document. The watermark will always be placed at the center of the document. See the Watermark section for more details.

String

Image file to add on top of the generated PDF. PDFShift will automatically detect if it's an URL or a data, and act accordingly. When sending as data, the value must be base64 encoded.

string

You can add a text as a watermark on your document easily.

Number

Size of the font, in points.

String

Font Family native to PDF. Allowed fonts are Helvetica, Times and Courier.

String

Color of the font, in hexadecimal.

Number

Opacity of the font, between 0 (invisible) and 100.

Boolean

Set the font in Bold.

Boolean

Set the font in italic.

Number

Rotation of the watermark, in degrees

POST /convert/pdf

Response

%PDF-1.4....
HTTP STatus code Description
200 - OK

Returns a pdf file.

400 - Bad Request

Bad request, returned when the request was not properly written.

401 - Unauthorized

Invalid api key given.

403 - Forbidden

No remaining credits left.

429 - Too Many Requests

You have been rate-limited.

Some interesting headers will also be returned in the successful response

Header Description
X-Pdfshift-Processor

Which backend processor was used

X-Process-Time

Complete duration of the request (including parsing, generating the response)

X-Response-Duration

Duration taken for the conversion (only)

X-Response-Status-Code

Status code received from the given source (if URL)

X-Credits-Used

How many credits this conversion used

X-Credits-Remaining

How many credits remains on your account

X-Request-Id

The request ID. Could be useful for debugging

Details

Margin

You can define margin for the document (space between the limits of the document and the beginning of the content).
You can either pass an object as defined below, or use a CSS like string, like the following:

Value Description
10px Will set a margin of 10px for all four borders.
10px 0 Will set a margin of 10px for top and bottom, and a margin of 0 for left and right.
10px 0 20px Will set a margin of 10px for top, 0 for left and right and 20px for the bottom.
10px 20px 30px 40px Will set a margin of 10px for top, 20px for right, 30px for bottom and 40px for left.

Otherwise, you can use an object to directly target a specific margin, using the following:

Parameter Type Default Description
top Integer or String null Space between the top and the content.
right Integer or String null Space between the right and the content.
bottom Integer or String null Space between the bottom and the content.
left Integer or String null Space between the left and the content.

You can configure the aspect of your header and footer document using the following values.

The footer and header are Independent from the rest of the document.

As such, the CSS style defined in your body won't apply on your header/footer.
To style your header/footer, you need to set a specific style either using <style> tag first, or adding style="" on your DOM elements.
Parameter Type Default Description
source String or URL null Element to add in the header/footer part of the document. You can use variables, indicated at the end of the document. PDFShift will automatically detect if it's an URL and load it, or an HTML data and charge it.
height Integer or String null A spacing between the header or footer and the content. For header, it's the space between the header and the beginning of the document. For the footer, it's the space between the end of the document and the bottom of the page.
start_at Integer 1 Start to display the header/footer at that given page. Important: If you send header AND footer, and set a start_at higher than 1, it must be the same for header and footer. For instance, header.start_at = 1 and footer.start_at = 5 is possible. But header.start_at = 2 and footer.start_at = 3 is NOT possible.
Variable Description
{{date}} Formatted print date
{{title}} Title of the HTML document
{{url}} Page URL
{{page}} Current page
{{total}} Total number of pages

Protection

You can restrict access to your generated document using the following rules. The encryption is made in 128bits.

Some PDF Reader don't make the distinction between user and owner in a PDF Document. This means that when the user password has been entered, some PDF reader ignore the restrictions (no print, no copy, etc).

So, setting a blank password for the user is similar to no security.

Parameter Type Default Description
author String null Document's author name
user_password String null A user who has the password will be able to view the document and perform operations allowed by the permission options
owner_password String null A user who has the password will have unlimited access to the PDF, including changing the passwords and permission options.
no_print Boolean false When set to true, printing will be disabled.
no_copy Boolean false When set to true, the possibility to copy any text will be disabled.
no_modify Boolean false When set to true, the possibility to modify the document will be disabled.

Watermark

You can add a watermark to your documents via these alternatives:

  • Via Text
  • Via Image

Each alternatives has a set of options, which is detailed here:

Via Text

Parameter Type Default Description
text String required The text to display as watermark.
font_size Integer 16 The font size used.
font_family String Helvetica The font family used.
font_color String 000000 The color of the text.
font_opacity Integer 100 The opacity for the text.
font_bold Boolean false Set to true if you want the text bold.
font_italic Boolean false Set to true if you want the text in italic.
offset_x String center The X position. Can be either a String (left, center, right) or a number with unit (defaults to pixels. Allowed units are 'px', 'in', 'cm', 'mm', 'pt').
offset_y String middle The Y position. Can be either a string (top, middle, bottom) or a number with unit (defaults to pixels. Allowed units are 'px', 'in', 'cm', 'mm', 'pt').
rotate Integer -45 The degree for the rotated element.

Via Image

Parameter Type Default Description
image URL or Base64 encoded image content required The image to display as watermark.
offset_x String center The X position. Can be either a String (left, center, right) or a number with unit (defaults to pixels. Allowed units are 'px', 'in', 'cm', 'mm', 'pt').
offset_y String middle The Y position. Can be either a string (top, middle, bottom) or a number with unit (defaults to pixels. Allowed units are 'px', 'in', 'cm', 'mm', 'pt').
rotate Integer -45 The degree for the rotated element.

Webhooks

When the conversion fail, we also do a POST request to your endpoint, but with an error key instead.
We recommend you to first check if the body contains the error before processing the document, and act accordingly.

If the webhook parameter is defined, the call to PDFShift's API will return a Queued response along with a 202 status code, like the following:

{"queued": true}

Once the processing has been done, we will send a POST request to your webhook endpoint, containing a JSON payload with the URL to your converted document, stored at Amazon S3 (for two days).

Here's a sample of the payload we will send you:

{
    "duration": 3121.766417985782,
    "filesize": 259972,
    "response": {
        "duration": 2562,
        "status-code": 200
    },
    "success": true,
    "url": "https://s3.amazonaws.com/pdfshift/d/2/2019-05/99c456250a01448686d81752a3fb5beb/15466098-8368-49e1-ac33-ff4c3941a0df.pdf"
}

In case there is any error while processing your document, we will instead send you a payload containing an error key, like the following:

{
    "error": {
        "code": 400,
        "error": "The requested page took too long to load.",
        "identifier": "A74",
        "success": false
    }
}

Saving to your Amazon S3

With PDFShift, you can save the converted PDF direclty into your S3 bucket at Amazon, allowing to post process it or deliver it to your clients using your own system.

In order to be able to save on your Bucket, you'll need to update the policy of your bucket destination.

We recommend you to use the following policy, but if you're an expert at AWS S3, feel free to customize it:

{
    "Version": "2012-10-17",
    "Statement": [{
        "Sid": "Only allow writes to this bucket with bucket owner full control",
        "Effect": "Allow",
        "Principal": {
            "AWS": ["arn:aws:iam::804461045055:user/pdfshift"]
        },
        "Action": ["s3:PutObject"],
        "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
        "Condition": {
            "StringEquals": {
                "s3:x-amz-acl": "bucket-owner-full-control"
            }
        }
    }]
}

(The file is also available at Pastebin)

Don't forget to change the name DOC-EXAMPLE-BUCKET to your appropriate bucket's name!

Once this policy in place, you'll be able to use the s3_destination parameter and use a value like s3://DOC-EXAMPLE-BUCKET/pdfshift/upload/86aa3ede7d05.pdf

Misc

When converting a document, if successful, the HTTP response from PDFShift's API will contain the following header:

Header Description
X-Response-StatusCode The status code from your URL source, when an URL is provided. This can be useful to ensure the URL worked correctly.

Examples

Converting an URL

The above command returns a PDF in binary format.

This endpoint the given URL to PDF.

// Use the code available at
// https://gist.github.com/cnicodeme/28ade69b269ca0a4af0a7c29c479b747

pdfshift.convert('your_api_key', { source: 'https://www.example.com' }).then(function (response) {
    fs.writeFile('example.com.pdf', response.data, "binary", function () {})
}).catch(function({message, code, response, errors = null}) {})
<?php
// Using the function at 
// https://gist.github.com/cnicodeme/f2c73d89ac49313d023d738b5cdb7046

$response = pdfshift('your_api_key', array (
    'source' => 'https://www.example.com'
));

file_put_contents('result.pdf', $response);
import requests

response = requests.post(
    'https://api.pdfshift.io/v3/convert/pdf',
    auth=('api', 'your_api_key'),
    json={'source': 'https://www.example.com'},
    stream=True
)

response.raise_for_status()

with open('result.pdf', 'wb') as output:
    for chunck in response.iter_content(chunk_size=1024):
        output.write(chunck)
require 'uri'
require 'net/https'
require 'json' # for hash to_json conversion

uri = URI("https://api.pdfshift.io/v3/convert/pdf")
data = {"source" => "https://www.example.com"}

Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
    request = Net::HTTP::Post.new(uri.request_uri)
    request.body = data.to_json
    request["Content-Type"] = "application/json"
    request.basic_auth 'api', 'your_api_key'

    response = http.request(request)

    if response.code == '200'
        # Since Ruby 1.9.1 only:
        File.binwrite("result.pdf", response.body)
    else
        # Handle other codes here
        puts "#{response.code} #{response.body}"
    end
end
public static void main(String... args) throws Exception {
    var jsonObject = new JSONObject();
    jsonObject.put("source", "https://example.com");
    var httpRequest = HttpRequest.newBuilder()
            .uri(URI.create("https://api.pdfshift.io/v3/convert/pdf"))
            .timeout(Duration.ofSeconds(20))
            .header("Content-Type", "application/json")
            .header("Authentication", "Basic " + "api:your_api_key")
            .POST(HttpRequest.BodyPublishers.ofString(jsonObject.toString()))
            .build();

    var httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .build();

    var response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream());

    var statusCode = response.statusCode();
    if (statusCode == 200 || statusCode == 201) {
        // Save the file locally
        var targetFile = new File("src/main/resources/targetFile.pdf");
        Files.copy(response.body(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
    } else {
        // error occurred
    }
}
static void Main(string[] args)
{
    IRestClient client = new RestClient("https://api.pdfshift.io/v3/convert/pdf");
    client.Authenticator = new HttpBasicAuthenticator("api", "your_api_key");

    IRestRequest request = new RestRequest(Method.POST);

    var json = new
    {
        source = "https://www.example.com"
    };
    request.AddJsonBody(json);

    IRestResponse response = client.Execute(request);
    if (!response.IsSuccessful)
    {
        // Check why status is not int 2xx.
    }
    else
    {
        File.WriteAllBytes("result.pdf", response.RawBytes);
    }
}
package main

import (
    "bytes"
    "encoding/json"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    API_KEY := "api:your_api_key"

    message := map[string]interface{}{
        "source":  "https://example.com",
    }

    bytesRepresentation, err := json.Marshal(message)
    if err != nil {
        log.Fatalln(err)
    }

    client := http.Client{}
    request, err := http.NewRequest("POST", "https://api.pdfshift.io/v3/convert/pdf", bytes.NewBuffer(bytesRepresentation))
    if err != nil {
        log.Fatalln(err)
    }
    request.SetBasicAuth("api", API_KEY)

    resp, err := client.Do(request)
    if err != nil {
        log.Fatalln(err)
    }

    if resp.StatusCode >= 200 && resp.StatusCode < 300 {
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            log.Fatalln(err)
        }
        // write the response to file
        ioutil.WriteFile("example.pdf", body, 0644)
    } else {
        // An error occurred
        var result map[string]interface{}

        json.NewDecoder(resp.Body).Decode(&result)

        log.Println(result)
        log.Println(result["data"])
    }
}

Saving the document to Amazon S3

The above command returns JSON structured like this:

{
  "success": true,
  "url": "https://s3.amazonaws.com/pdfshift/d/2/2019-02/47fc3918791a4818a6bf655cfb63c96e/result.pdf",
  "filesize": 13370,
  "duration": 5
}

By passing the "filename" parameter, the endpoint won't return the binary PDF, but an URL from Amazon S3 where the document will be stored for 2 days before being automatically deleted.

This can be useful if you don't want to download a large PDF to your server to then serve it to your users, but instead redirect them directly to that document.

// Use the code available at
// https://gist.github.com/cnicodeme/28ade69b269ca0a4af0a7c29c479b747

pdfshift.convert('your_api_key', { source: 'https://www.example.com', filename: 'result.pdf' }).then(function (response) {
    // The URL is on 
    console.log(response.data.url);
}).catch(function({message, code, response, errors = null}) {})
<?php
$response = pdfshift('your_api_key', array (
    'source' => 'https://www.example.com',
    'filename' => 'result.pdf'
));

$json = json_decode($response, true);
// The URL is at $json['url'];
import requests

response = requests.post(
    'https://api.pdfshift.io/v3/convert/pdf',
    auth=('api', 'your_api_key'),
    json={
        'source': 'https://www.example.com',
        'filename': 'result.pdf'
    }
)

response.raise_for_status()

json_response = response.json()
# The URL to the document is at json_response['url]
require 'uri'
require 'net/https'
require 'json' # for hash to_json conversion

uri = URI("https://api.pdfshift.io/v3/convert/pdf")
data = { "source" => 'http://www.example.com',
    "filename" => "result.pdf" }

Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
    request = Net::HTTP::Post.new(uri.request_uri)
    request.body = data.to_json
    request["Content-Type"] = "application/json"
    request.basic_auth 'api', 'your_api_key'

    response = http.request(request)

    if response.code == '200'
        puts response.body
        # { "duration":1309,
        # "filesize":37511,
        # "success":true,
        # "url":"<amazon_s3_url>/result.pdf"}
        data = JSON.parse(response.body)
        redirect_to data['url']
    else
        # Handle other codes here
        puts "#{response.code} #{response.body}"
    end
end
public static void main(String... args) throws Exception {
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("source", "https://example.com");
    jsonObject.put("filename", "result.pdf");

    var httpRequest = HttpRequest.newBuilder()
            .uri(URI.create("https://api.pdfshift.io/v3/convert/pdf"))
            .timeout(Duration.ofSeconds(20))
            .header("Content-Type", "application/json")
            .header("Authentication", "Basic " + "your_api_key")
            .POST(HttpRequest.BodyPublishers.ofFile(Paths.get("src/main/resources/body.json")))
            .build();

    var httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .build();

    var response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

    var statusCode = response.statusCode();
    if (statusCode == 200 || statusCode == 201) {
        // Response body is a json string. 
        var result = new JSONObject(response.body());
        System.out.println(result.get("url"));
    } else {
        // error occurred
    }
}
static void Main(string[] args)
{
    IRestClient client = new RestClient("https://api.pdfshift.io/v3/convert/pdf");
    client.Authenticator = new HttpBasicAuthenticator("api", "your_api_key");

    IRestRequest request = new RestRequest(Method.POST);

    var json = new
    {
        source = "https://www.example.com",
        filename = "result.pdf"
    };
    request.AddJsonBody(json);

    IRestResponse response = client.Execute(request);
    if (!response.IsSuccessful)
    {
        // Check why status is not int 2xx.
    }
    else
    {
        var jObject = JObject.Parse(response.Content);
        Console.WriteLine(jObject["url"].Value<string>());
    }
}
package main

import (
    "net/http"
    "log"
    "encoding/json"
    "bytes"

)

func main() {
    API_KEY := "api:your_api_key"

    message := map[string]interface{}{
        "source": "https://example.com",
        "filename": "anotherExample.pdf",
    }

    bytesRepresentation, err := json.Marshal(message)
    if err != nil {
        log.Fatalln(err)
    }

    client := http.Client{}
    request, err := http.NewRequest("POST", "https://api.pdfshift.io/v3/convert/pdf", bytes.NewBuffer(bytesRepresentation))
    if err != nil {
        log.Fatalln(err)
    }
    request.SetBasicAuth("api", API_KEY)

    resp, err := client.Do(request)
    if err != nil {
        log.Fatalln(err)
    }

    if resp.StatusCode >= 200 && resp.StatusCode < 300 {
        var result map[string]interface{}

        json.NewDecoder(resp.Body).Decode(&result)

        log.Println(result["url"])
    } else {
        // An error occurred
        var result map[string]interface{}

        json.NewDecoder(resp.Body).Decode(&result)

        log.Println(result)
    }
}

Accessing secured pages

The above command returns a PDF in binary format.

If your documents are located inside a protected area requiring a Basic Auth access, you can use the auth parameter from PDFShift's API to connect to your website.
Here's an example on how to do so.

// Use the code available at
// https://gist.github.com/cnicodeme/28ade69b269ca0a4af0a7c29c479b747

pdfshift.convert('your_api_key', { source: 'https://httpbin.org/basic-auth/user/passwd', auth: { user: 'user', pass: 'passwd' } }).then(function (response) {
    fs.writeFileSync('basic-auth.pdf', response.data, "binary", function () {})
})
<?php
$response = pdfshift('your_api_key', array (
    'source' => 'https://httpbin.org/basic-auth/user/passwd',
    'auth' => array (
        'username' => 'user',
        'password' => 'passwd'
    )
));

file_put_contents('basic-auth.pdf', $response);
import requests

response = requests.post(
    'https://api.pdfshift.io/v3/convert/pdf',
    auth=('api', 'your_api_key'),
    json={
        'source': 'https://httpbin.org/basic-auth/user/passwd',
        'auth': {
            'username': 'user',
            'password': 'passwd'
        }
    },
    stream=True
)

response.raise_for_status()

with open('basic-auth.pdf', 'wb') as output:
    for chunck in response.iter_content(chunk_size=1024):
        output.write(chunck)
require 'uri'
require 'net/https'
require 'json' # for hash to_json conversion

uri = URI("https://api.pdfshift.io/v3/convert/pdf")
data = {"source" => "https://httpbin.org/basic-auth/user/passwd",
    "auth" => {
        "username" => "user",
        "password" => "passwd"
    } }

Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
    request = Net::HTTP::Post.new(uri.request_uri)
    request.body = data.to_json
    request["Content-Type"] = "application/json"
    request.basic_auth 'api', 'your_api_key'

    response = http.request(request)

    if response.code == '200'
        # Since Ruby 1.9.1 only:
        File.binwrite("basic-auth.pdf", response.body)
    else
        # Handle other codes here
        puts "#{response.code} #{response.body}"
    end
end
public static void main(String... args) throws Exception {
    var jsonObject = new JSONObject();
    jsonObject.put("source", "https://httpbin.org/basic-auth/user/passwd");

    var auth = new JSONObject();
    auth.put("username", "user");
    auth.put("password", "passwd");

    jsonObject.put("auth", auth);

    var httpRequest = HttpRequest.newBuilder()
            .uri(URI.create("https://api.pdfshift.io/v3/convert/pdf"))
            .timeout(Duration.ofSeconds(20))
            .header("Content-Type", "application/json")
            .header("Authentication", "Basic " + "api:your_api_key")
            .POST(HttpRequest.BodyPublishers.ofString(jsonObject.toString()))
            .build();

    var httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .build();

    var response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream());

    var statusCode = response.statusCode();
    if (statusCode == 200 || statusCode == 201) {
        // Save the file locally
        var targetFile = new File("src/main/resources/basic-auth.pdf");
        Files.copy(response.body(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
    } else {
        // error occurred
    }
}
static void Main(string[] args)
{
    IRestClient client = new RestClient("https://api.pdfshift.io/v3/convert/pdf");
    client.Authenticator = new HttpBasicAuthenticator("api", "your_api_key");

    IRestRequest request = new RestRequest(Method.POST);

    var json = new
    {
        source = "https://httpbin.org/basic-auth/user/passwd",
        auth = new { username = "user", password = "passwd" }
    };
    request.AddJsonBody(json);

    IRestResponse response = client.Execute(request);
    if (!response.IsSuccessful)
    {
        // Check why status is not int 2xx.
    }
    else
    {
        File.WriteAllBytes("basic-auth.pdf", response.RawBytes);
    }
}
package main

import (
    "bytes"
    "encoding/json"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    API_KEY := "api:your_api_key"

    message := map[string]interface{}{
        "source": "https://httpbin.org/basic-auth/user/passwd",
        "auth": map[string]string{
            "username": "user",
            "password": "passwd",
        },
    }

    bytesRepresentation, err := json.Marshal(message)
    if err != nil {
        log.Fatalln(err)
    }

    client := http.Client{}
    request, err := http.NewRequest("POST", "https://api.pdfshift.io/v3/convert/pdf", bytes.NewBuffer(bytesRepresentation))
    if err != nil {
        log.Fatalln(err)
    }
    request.SetBasicAuth("api", API_KEY)

    resp, err := client.Do(request)
    if err != nil {
        log.Fatalln(err)
    }

    if resp.StatusCode >= 200 && resp.StatusCode < 300 {
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            log.Fatalln(err)
        }
        // write the response to file
        ioutil.WriteFile("basic-auth.pdf", body, 0644)
    } else {
        var result map[string]interface{}

        json.NewDecoder(resp.Body).Decode(&result)

        log.Println(result)
    }
}

Using Cookies

The above command returns a PDF in binary format.

On the contrary, if your endpoint requires a more advanced authentication format, like a PHP session.
You can add cookies to the parameter to simulate an active session.

This can be easily done with the cookies parameter from our API.

// Use the code available at
// https://gist.github.com/cnicodeme/28ade69b269ca0a4af0a7c29c479b747

pdfshift.convert('your_api_key', { source: 'https://httpbin.org/cookies', cookies: [{name: 'session', value: '4cb496a8-a3eb-4a7e-a704-f993cb6a4dac'}] }).then(function (response) {
    fs.writeFileSync('cookies.pdf', response.data, "binary", function () {})
})
<?php
$response = pdfshift('your_api_key', array (
    'source' => 'https://httpbin.org/cookies',
    'cookies' => array(array ('name' => 'session', 'value' => '4cb496a8-a3eb-4a7e-a704-f993cb6a4dac'))
));

file_put_contents('cookies.pdf', $response);
import requests

response = requests.post(
    'https://api.pdfshift.io/v3/convert/pdf',
    auth=('api', 'your_api_key'),
    json={
        'source': 'https://httpbin.org/cookies',
        'cookies': [{'name': 'session', 'value': '4cb496a8-a3eb-4a7e-a704-f993cb6a4dac'}]
    },
    stream=True
)

response.raise_for_status()

with open('cookies.pdf', 'wb') as output:
    for chunck in response.iter_content(chunk_size=1024):
        output.write(chunck)
require 'uri'
require 'net/https'
require 'json' # for hash to_json conversion

uri = URI("https://api.pdfshift.io/v3/convert/pdf")
data = {"source" => "https://httpbin.org/cookies",
    "cookies" => [{"name" => "session",
    "value" => "4cb496a8-a3eb-4a7e-a704-f993cb6a4dac" }] }

Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
    request = Net::HTTP::Post.new(uri.request_uri)
    request.body = data.to_json
    request["Content-Type"] = "application/json"
    request.basic_auth 'api', 'your_api_key'

    response = http.request(request)

    if response.code == '200'
        # Since Ruby 1.9.1 only:
        File.binwrite("cookies.pdf", response.body)
    else
        # Handle other codes here
        puts "#{response.code} #{response.body}"
    end
end
public static void main(String... args) throws Exception {
    var jsonObject = new JSONObject();
    jsonObject.put("source", "https://httpbin.org/cookies");

    var cookie = new JSONObject();
    cookie.put("name", "session");
    cookie.put("value", "4cb496a8-a3eb-4a7e-a704-f993cb6a4dac");

    var cookies = new JSONArray();
    cookies.put(cookie);

    jsonObject.put("cookies", cookies);

    var httpRequest = HttpRequest.newBuilder()
            .uri(URI.create("https://api.pdfshift.io/v3/convert/pdf"))
            .timeout(Duration.ofSeconds(20))
            .header("Content-Type", "application/json")
            .header("Authentication", "Basic " + "api:your_api_key")
            .POST(HttpRequest.BodyPublishers.ofString(jsonObject.toString()))
            .build();

    var httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .build();

    var response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream());

    var statusCode = response.statusCode();
    if (statusCode == 200 || statusCode == 201) {
        // Save the file locally
        var targetFile = new File("src/main/resources/cookies.pdf");
        Files.copy(response.body(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
    } else {
        // error occurred
    }
}
static void Main(string[] args)
{
    IRestClient client = new RestClient("https://api.pdfshift.io/v3/convert/pdf");
    client.Authenticator = new HttpBasicAuthenticator("api", "your_api_key");

    IRestRequest request = new RestRequest(Method.POST);

    var json = new
    {
        source = "https://httpbin.org/cookies",
        cookies = new object[] { new { name = "Session", value = "4cb496a8-a3eb-4a7e-a704-f993cb6a4dac" } }
    };
    request.AddJsonBody(json);

    IRestResponse response = client.Execute(request);
    if (!response.IsSuccessful)
    {
        // Check why status is not int 2xx.
    }
    else
    {
        File.WriteAllBytes("cookies.pdf", response.RawBytes);
    }
}
package main

import (
    "net/http"
    "log"
    "encoding/json"
    "bytes"
    "io/ioutil"

)

func main() {
    API_KEY := "api:your_api_key"

    cookies := make([]map[string]string, 1)

    cookies[0] = make(map[string]string)
    cookies[0]["name"] = "session"
    cookies[0]["value"] = "4cb496a8-a3eb-4a7e-a704-f993cb6a4dac"

    message := map[string]interface{}{
        "source": "<html><head><title>Hello world</title><body><h1>Hello World</h1></body></head></html>",
        "cookies": cookies,
    }

    bytesRepresentation, err := json.Marshal(message)
    if err != nil {
        log.Fatalln(err)
    }

    client := http.Client{}
    request, err := http.NewRequest("POST", "https://api.pdfshift.io/v3/convert/pdf", bytes.NewBuffer(bytesRepresentation))
    if err != nil {
        log.Fatalln(err)
    }
    request.SetBasicAuth("api", API_KEY)

    resp, err := client.Do(request)
    if err != nil {
        log.Fatalln(err)
    }

    if resp.StatusCode >= 200 && resp.StatusCode < 300 {
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            log.Fatalln(err)
        }
        // write the response to file
        ioutil.WriteFile("cookies.pdf", body, 0644)
    } else {
        var result map[string]interface{}

        json.NewDecoder(resp.Body).Decode(&result)

        log.Println(result)
    }
}

The above command returns a PDF in binary format.

One frequent action when converting a web document to PDF is to add header and footer.
This is useful to add page number for instance, or the name of your company at the top of each pages.

This is easily done in PDFShift with the header/footer parameter.

// Use the code available at
// https://gist.github.com/cnicodeme/28ade69b269ca0a4af0a7c29c479b747

pdfshift.convert('your_api_key', { source: 'https://www.example.com', footer: { source: '<div>Page {{page}} of {{total}}</div>', height: '50px' } }).then(function (response) {
    fs.writeFileSync('footer.pdf', response.data, "binary", function () {})
})

<?php
$response = pdfshift('your_api_key', array (
    'source' => 'https://www.example.com',
    'footer' => array (
        'source' => '<div style="font-size: 12px">Page {{ "{{page}}" }} of {{ "{{total}}" }}</div>',
        'height' => '50px'
    )
));

file_put_contents('footer.pdf', $response);
import requests

response = requests.post(
    'https://api.pdfshift.io/v3/convert/pdf',
    auth=('api', 'your_api_key'),
    json={
        'source': 'https://www.example.com',
        'footer': {
            'source': '<div style="font-size: 12px">Page {{ "{{page}}" }} of {{ "{{total}}" }}</div>',
            'height': '50px'
        }
    },
    stream=True
)

response.raise_for_status()

with open('footer.pdf', 'wb') as output:
    for chunck in response.iter_content(chunk_size=1024):
        output.write(chunck)
require 'uri'
require 'net/https'
require 'json' # for hash to_json conversion

uri = URI("https://api.pdfshift.io/v3/convert/pdf")
data = {"source" => "https://www.example.com",
    'footer' => {
        'source' => '<div style="font-size: 12px">Page {{ "{{page}}" }} of {{ "{{total}}" }}</div>',
        'height' => '50px'
    } }

Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
    request = Net::HTTP::Post.new(uri.request_uri)
    request.body = data.to_json
    request["Content-Type"] = "application/json"
    request.basic_auth 'api', 'your_api_key'

    response = http.request(request)

    if response.code == '200'
        # Since Ruby 1.9.1 only:
        File.binwrite("footer.pdf", response.body)
    else
        # Handle other codes here
        puts "#{response.code} #{response.body}"
    end
end
public static void main(String... args) throws Exception {
    var jsonObject = new JSONObject();
    jsonObject.put("source", "https://www.example.com");

    var footer = new JSONObject();
    footer.put("source", "<div style='font-size: 12px'>Page {{ "{{page}}" }} of {{ "{{total}}" }}</div>");
    footer.put("height", "50px");

    jsonObject.put("footer", footer);

    var httpRequest = HttpRequest.newBuilder()
            .uri(URI.create("https://api.pdfshift.io/v3/convert/pdf"))
            .timeout(Duration.ofSeconds(20))
            .header("Content-Type", "application/json")
            .header("Authentication", "Basic " + "api:your_api_key")
            .POST(HttpRequest.BodyPublishers.ofString(jsonObject.toString()))
            .build();

    var httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .build();

    var response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream());

    var statusCode = response.statusCode();
    if (statusCode == 200 || statusCode == 201) {
        // Save the file locally
        var targetFile = new File("src/main/resources/footer.pdf");
        Files.copy(response.body(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
    } else {
        // error occurred
    }
}
static void Main(string[] args)
{
    IRestClient client = new RestClient("https://api.pdfshift.io/v3/convert/pdf");
    client.Authenticator = new HttpBasicAuthenticator("api", "your_api_key");

    IRestRequest request = new RestRequest(Method.POST);

    var json = new
    {
        source = "https://www.example.com",
        footer = new { source = "<div style=\"font-size: 12px\">Page {{ "{{page}}" }} of {{ "{{total}}" }}</div>", height = "50px" }
    };
    request.AddJsonBody(json);

    IRestResponse response = client.Execute(request);
    if (!response.IsSuccessful)
    {
        // Check why status is not int 2xx.
    }
    else
    {
        File.WriteAllBytes("footer.pdf", response.RawBytes);
    }
}
package main

import (
    "bytes"
    "encoding/json"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    API_KEY := "api:your_api_key"

    message := map[string]interface{}{
        "source": "https://www.example.com",
        "footer": map[string]string{
            "source": "<div style='font-size: 12px'>Page {{ "{{page}}" }} of {{ "{{total}}" }}</div>",
            "height": "50px",
        },
    }

    bytesRepresentation, err := json.Marshal(message)
    if err != nil {
        log.Fatalln(err)
    }

    client := http.Client{}
    request, err := http.NewRequest("POST", "https://api.pdfshift.io/v3/convert/pdf", bytes.NewBuffer(bytesRepresentation))
    if err != nil {
        log.Fatalln(err)
    }
    request.SetBasicAuth("api", API_KEY)

    resp, err := client.Do(request)
    if err != nil {
        log.Fatalln(err)
    }

    if resp.StatusCode >= 200 && resp.StatusCode < 300 {
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            log.Fatalln(err)
        }
        // write the response to file
        ioutil.WriteFile("footer.pdf", body, 0644)
    } else {
        var result map[string]interface{}

        json.NewDecoder(resp.Body).Decode(&result)

        log.Println(result)
    }
}

Sending an invoice by email

The above command returns a PDF in binary format.

Here's a complete example of how PDFShift can be integrated in one of your project.

A frequent use case is to use PDFShift to convert a locally generated invoice made in HTML (displayed in the back-office of your customer), converted in PDF and then sent by email.

// Use the code available at
// https://gist.github.com/cnicodeme/28ade69b269ca0a4af0a7c29c479b747

const express = require('express');
const fs = require('fs');
const nodemail = require('nodemailer');

const app = express();

app.get('/send/',  (req, res, next) => {
    let invoice = fs.readFileSync('invoice.html', 'utf8');

    pdfshift.convert('your_api_key', { source: invoice }).then(function (response) {
        let transporter = nodemailer.createTransport({
            host: "smtp.gmail.com",
            port: 587,
            secure: true,
            auth: {
                user: account.user,
                pass: account.pass
            }
        });

        let mailOptions = {
            from: '"Billing at Your-Site" <[email protected]>',
            to: "[email protected]"
            subject: "Thank you for your purchase",
            text: fs.readFileSync('templates/emails/invoice.txt', 'utf8'),
            html: fs.readFileSync('templates/emails/invoice.html', 'utf8'),
            attachments: [
                {
                    filename: 'invoice.pdf',
                    contentType: 'application/pdf',
                    content: response.data
                }
            ]
        };

        // send mail with defined transport object
        await transporter.sendMail(mailOptions)

        // Then, we redirect
        res.redirect(301, '/thank-you');
    })
})
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'path/to/PHPMailer/src/Exception.php';
require 'path/to/PHPMailer/src/PHPMailer.php';
require 'path/to/PHPMailer/src/SMTP.php';

$source = file_get_contents('invoice.html');

$binary_pdf = pdfshift('your_api_key', array (
    'source' => $source
));

$mail = new PHPMailer(true);
try {
    $mail->isSMTP();
    $mail->Host = 'smtp1.example.com;smtp2.example.com';
    $mail->SMTPAuth = true;
    $mail->Username = '[email protected]';
    $mail->Password = 'secret';
    $mail->SMTPSecure = 'tls';
    $mail->Port = 587;

    $mail->setFrom('[email protected]', 'Billing at Your-Site');
    $mail->addAddress('[email protected]', 'John Doe');

    // Body of the email
    $mail->isHTML(true);
    $mail->Subject = 'Thank you for your purchase';
    $mail->Body    = file_get_contents('templates/emails/invoice.html');
    $mail->AltBody = file_get_contents('templates/emails/invoice.txt');

    // Add the invoice from PDFShift:
    $mail->addStringAttachment($binary_pdf, 'invoice.pdf', 'base64', 'application/pdf');

    $mail->send();
    return redirect('/thank-you');
} catch (Exception $e) {
    // Manage exception
}
from django.core.mail import EmailMultiAlternatives
from django.shortcuts import redirect
import requests

document = open('invoice.html', 'r')
document_content = document.read()
document.close()

response = requests.post(
    'https://api.pdfshift.io/v3/convert/pdf',
    auth=('api', 'your_api_key'),
    json={'source': document_content}
)

response.raise_for_status()

text_content = None
with open('templates/emails/invoice.txt', 'r') as f:
    text_content = f.read()

html_content = None
with open('templates/emails/invoice.html', 'r') as f:
    html_content = f.read()

msg = EmailMultiAlternatives("Thank you for your purchase", text_content, '[email protected]', ['[email protected]'])
msg.attach_alternative(html_content, "text/html")
msg.attach('invoice.pdf', response.content, 'application/pdf')
msg.send()

return redirect('/thank-you')
require 'uri'
require 'net/https'
require 'json'
require 'net/smtp'
require 'mail'
require 'sinatra'

get '/send' do
    generate_invoice
    send_invoice_via_email
    redirect to('/thank-you')
end

get '/thank-you' do
    'Check your email! thanks for using PDFShift!'
end

def generate_invoice
    file = File.read("invoice.html")
    uri = URI("https://api.pdfshift.io/v3/convert/pdf")
    data = {"source" => file}

    Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
        request = Net::HTTP::Post.new(uri.request_uri)
        request.body = data.to_json
        request["Content-Type"] = "application/json"
        request.basic_auth 'api', 'your_api_key'

        response = http.request(request)

        if response.code == '200'
            File.binwrite("result.pdf", response.body)
        else
            puts "#{response.code} #{response.body}"
        end
    end
end

def send_invoice_via_email
    # Update user_name and password with a valid gmail account
    options = { :address              => "smtp.gmail.com",
                :port                 => 587,
                :domain               => 'pdfshift.io',
                :user_name            => '[email protected]',
                :password             => 'examplepassword',
                :authentication       => 'plain',
                :enable_starttls_auto => true }

    Mail.defaults do
        delivery_method :smtp, options
    end

    # Update the email fields to your needs
    Mail.deliver do
        from     '[email protected]'
        to       '[email protected]'
        subject  'Your invoice'
        body     "Here's the invoice you requested"
        add_file 'result.pdf'
    end
end
public static void main(String... args) throws Exception {
    byte[] encoded = Files.readAllBytes(Paths.get("src/main/resources/example.html"));
    String documentContent = new String(encoded, Charset.defaultCharset());

    var jsonObject = new JSONObject();
    jsonObject.put("source", documentContent);

    var httpRequest = HttpRequest.newBuilder()
            .uri(URI.create("https://api.pdfshift.io/v3/convert/pdf"))
            .timeout(Duration.ofSeconds(10))
            .header("Content-Type", "application/json")
            .header("Authentication", "Basic " + "api:your_api_key")
            .POST(HttpRequest.BodyPublishers.ofString(jsonObject.toString()))
            .build();

    var httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .build();
    var response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofInputStream());

    var statusCode = response.statusCode();
    if (statusCode == 200 || statusCode == 201) {
        // save pdf to file targetFile.pdf
        var targetFile = new File("src/main/resources/targetFile.pdf");
        Files.copy(response.body(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

        // Send pdf as email attachment
        var prop = new Properties();
        prop.put("mail.smtp.auth", true);
        prop.put("mail.smtp.starttls.enable", "true");
        prop.put("mail.smtp.host", "smtp.mailtrap.io");
        prop.put("mail.smtp.port", "25");
        prop.put("mail.smtp.ssl.trus", "smtp.mailtrap.io");

        var username = "get username from mailtrap.io";
        var password = "get password from mailtrap.io";

        var session = Session.getInstance(prop, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        });

        var message = new MimeMessage(session);
        message.setFrom(new InternetAddress("[email protected]"));
        message.setRecipients(
                Message.RecipientType.TO, InternetAddress.parse("[email protected]")
        );
        message.setSubject("Mail Subject");

        var attachment = new File("src/main/resources/targetFile.pdf");

        var mimeBodyPart = new MimeBodyPart();
        mimeBodyPart.setContent("Just ignore this message", "text/plain");
        mimeBodyPart.attachFile(attachment);

        var multipart = new MimeMultipart();
        multipart.addBodyPart(mimeBodyPart);

        message.setContent(multipart);

        Transport.send(message);
    } else {
        System.out.println("Error occured");
    }
}
static void Main(string[] args)
{
    IRestClient client = new RestClient("https://api.pdfshift.io/v3/convert/pdf");
    client.Authenticator = new HttpBasicAuthenticator("api", "your_api_key");

    IRestRequest request = new RestRequest(Method.POST);
    string document_content = File.ReadAllText("invoice.html");
    var json = new
    {
        source = document_content,
        sandbox = true,
    };
    request.AddJsonBody(json);
    IRestResponse response = client.Execute(request);

    if (!response.IsSuccessful)
    {
        // Check why status is not int 2xx.
    }

    SmtpClient smtpClient = new SmtpClient();
    smtpClient.EnableSsl = true;
    NetworkCredential basicCredential = new NetworkCredential("YourMail", "YourPassword");
    MailMessage message = new MailMessage();
    MailAddress fromAddress = new MailAddress("[email protected]");

    // setup up the host, increase the timeout to 5 minutes
    smtpClient.Host = "smtp.gmail.com";
    smtpClient.UseDefaultCredentials = false;
    smtpClient.Credentials = basicCredential;
    smtpClient.Timeout = (60 * 5 * 1000);

    message.From = fromAddress;
    message.Subject = "Thank you for your purchase";
    message.IsBodyHtml = false;
    message.Body = File.ReadAllText("templates/emails/invoice.html");
    message.To.Add("[email protected]");

    Attachment attachment;
    using (MemoryStream stream = new MemoryStream(response.RawBytes))
    {
        attachment = new Attachment(stream, "invoice.pdf");
        message.Attachments.Add(attachment);
    }

    smtpClient.Send(message);
}
package main

import (
    "bytes"
    "encoding/json"
    "io/ioutil"
    "log"
    "net/http"
    "net/mail"
    "net/smtp"

    "github.com/scorredoira/email"
)

func main() {
    API_KEY := "api:your_api_key"

    encoded, err := ioutil.ReadFile("example.html")
    if err != nil {
        log.Fatalln(err)
    }

    documentContent := string(encoded)

    message := map[string]interface{}{
        "source":  documentContent,
        "sandbox": true,
    }

    bytesRepresentation, err := json.Marshal(message)
    if err != nil {
        log.Fatalln(err)
    }

    client := http.Client{}
    request, err := http.NewRequest("POST", "https://api.pdfshift.io/v3/convert/pdf", bytes.NewBuffer(bytesRepresentation))
    if err != nil {
        log.Fatalln(err)
    }
    request.SetBasicAuth("api", API_KEY)

    resp, err := client.Do(request)
    if err != nil {
        log.Fatalln(err)
    }

    if resp.StatusCode >= 200 && resp.StatusCode < 300 {
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            log.Fatalln(err)
        }
                // write the response to file
                ioutil.WriteFile("example.pdf", body, 0644)

        // Send email
                m := email.NewMessage("Hi", "This is an example converted file")
                m.From = mail.Address{Name: "From", Address: "[email protected]"}
                m.To = []string{"[email protected]"}

                if err := m.Attach("example.pdf"); err != nil {
                    log.Fatalln(err)
                }

                auth := smtp.PlainAuth("", "c33e0593149230", "84d1dec05f668b", "smtp.mailtrap.io")
                if err := email.Send("smtp.mailtrap.io:2525", auth, m); err != nil {
                    log.Fatalln(err)
                }
    } else {
        // An error occurred
        var result map[string]interface{}

        json.NewDecoder(resp.Body).Decode(&result)

        log.Println(result)
        log.Println(result["data"])
    }
}

Credits

Credits usage

Returns the current credits usage.

GET /credits/usage

Response

{
    "credits": {
        "base": 50000,
        "remaining": 49881,
        "total": 50000,
        "used": 119
    },
    "success": true
}
HTTP STatus code Description
200 - OK

Returns a valid json containing the credits details.