Skip to main content
With PDFShift, you can save the converted PDF directly into your Cloudflare R2 bucket, allowing you to post process it or deliver it to your clients using your own system. Unlike the other S3-compatible providers we support, R2 does not accept a bucket policy that grants PDFShift write access to your bucket. Instead, you generate a pre-signed URL on your side that authorizes a single PutObject upload, and you hand that URL to PDFShift as the destination. This means you keep full control: the credentials never leave your infrastructure, and the URL you generate is short-lived and scoped to one specific object.

1. Generate a pre-signed URL

Following Cloudflare’s guide on pre-signed URLs, create an R2 API token (Access Key ID + Secret Access Key) and use it with any S3-compatible client to sign a PutObject request. Point the S3 client at your R2 endpoint, which has the form:
https://<ACCOUNT_ID>.r2.cloudflarestorage.com
Here is an example using Python and boto3:
import boto3
from botocore.config import Config

s3 = boto3.client(
    "s3",
    endpoint_url="https://<ACCOUNT_ID>.r2.cloudflarestorage.com",
    aws_access_key_id="<ACCESS_KEY_ID>",
    aws_secret_access_key="<SECRET_ACCESS_KEY>",
    config=Config(signature_version="s3v4"),
    region_name="auto",
)

presigned_url = s3.generate_presigned_url(
    "put_object",
    Params={
        "Bucket": "DOC-EXAMPLE-BUCKET",
        "Key": "pdfshift/upload/86aa3ede7d05.pdf",
    },
    ExpiresIn=3600,  # valid for 1 hour
)

print(presigned_url)
Or with the AWS SDK for JavaScript (v3):
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const S3 = new S3Client({
  region: "auto",
  endpoint: "https://<ACCOUNT_ID>.r2.cloudflarestorage.com",
  credentials: {
    accessKeyId: "<ACCESS_KEY_ID>",
    secretAccessKey: "<SECRET_ACCESS_KEY>",
  },
});

const presignedUrl = await getSignedUrl(
  S3,
  new PutObjectCommand({
    Bucket: "DOC-EXAMPLE-BUCKET",
    Key: "pdfshift/upload/86aa3ede7d05.pdf",
  }),
  { expiresIn: 3600 }
);
The pre-signed URL must authorize the PutObject action, since PDFShift uploads the generated PDF. A URL signed for any other action (such as GetObject) will be rejected.

2. Pass the URL to PDFShift

The URL returned by the client will look like the following:
https://<ACCOUNT_ID>.r2.cloudflarestorage.com/DOC-EXAMPLE-BUCKET/pdfshift/upload/86aa3ede7d05.pdf?X-Amz-Algorithm=...&X-Amz-Credential=...&X-Amz-Signature=...
Use that full URL as the value of the s3_destination parameter. PDFShift detects the r2.cloudflarestorage.com host and uploads the converted PDF straight to your bucket using the signature you provided.
Don’t forget to change DOC-EXAMPLE-BUCKET to your appropriate bucket’s name, and <ACCOUNT_ID> / the credentials to your own values!