Wasabi
Prerequisites
- A PolyDoc account and API key — sign up for free, no credit card required. The free plan includes 150 PDF conversions per month.
- A Wasabi account with a bucket. Create a bucket
- An access key pair with write access to the target bucket.
Integration
Generate a presigned URL
Wasabi is fully S3-compatible, so you can use the AWS SDK with Wasabi's endpoint. No special SDK is needed.
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
// npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
const s3 = new S3Client({
region: "eu-central-1",
endpoint: "https://s3.eu-central-1.wasabisys.com",
credentials: {
accessKeyId: process.env.WASABI_ACCESS_KEY,
secretAccessKey: process.env.WASABI_SECRET_KEY,
},
});
const presignedUrl = await getSignedUrl(
s3,
new PutObjectCommand({
Bucket: "my-bucket",
Key: "invoices/inv-001.pdf",
ContentType: "application/pdf",
}),
{ expiresIn: 300 } // 5 minutes
);
import boto3
import os
# pip install boto3
s3 = boto3.client(
"s3",
region_name="eu-central-1",
endpoint_url="https://s3.eu-central-1.wasabisys.com",
aws_access_key_id=os.environ["WASABI_ACCESS_KEY"],
aws_secret_access_key=os.environ["WASABI_SECRET_KEY"],
)
presigned_url = s3.generate_presigned_url(
"put_object",
Params={
"Bucket": "my-bucket",
"Key": "invoices/inv-001.pdf",
"ContentType": "application/pdf",
},
ExpiresIn=300,
)
require "aws-sdk-s3"
# gem install aws-sdk-s3
s3 = Aws::S3::Resource.new(
region: "eu-central-1",
endpoint: "https://s3.eu-central-1.wasabisys.com",
credentials: Aws::Credentials.new(
ENV["WASABI_ACCESS_KEY"],
ENV["WASABI_SECRET_KEY"]
)
)
presigner = Aws::S3::Presigner.new(client: s3.client)
presigned_url = presigner.presigned_url(
:put_object,
bucket: "my-bucket",
key: "invoices/inv-001.pdf",
expires_in: 300,
content_type: "application/pdf"
)
package main
import (
"context"
"fmt"
"os"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
func main() {
cfg, _ := config.LoadDefaultConfig(context.TODO(),
config.WithRegion("eu-central-1"),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
os.Getenv("WASABI_ACCESS_KEY"), os.Getenv("WASABI_SECRET_KEY"), "",
)),
)
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String("https://s3.eu-central-1.wasabisys.com")
})
presignClient := s3.NewPresignClient(client)
req, _ := presignClient.PresignPutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("invoices/inv-001.pdf"),
ContentType: aws.String("application/pdf"),
}, s3.WithPresignExpires(5*time.Minute))
fmt.Println(req.URL)
}
<?php
require 'vendor/autoload.php';
// composer require aws/aws-sdk-php
use Aws\S3\S3Client;
$s3 = new S3Client([
'version' => 'latest',
'region' => 'eu-central-1',
'endpoint' => 'https://s3.eu-central-1.wasabisys.com',
'credentials' => [
'key' => getenv('WASABI_ACCESS_KEY'),
'secret' => getenv('WASABI_SECRET_KEY'),
],
]);
$cmd = $s3->getCommand('PutObject', [
'Bucket' => 'my-bucket',
'Key' => 'invoices/inv-001.pdf',
'ContentType' => 'application/pdf',
]);
$request = $s3->createPresignedRequest($cmd, '+5 minutes');
$presignedUrl = (string) $request->getUri();
use aws_config::BehaviorVersion;
use aws_sdk_s3::{
config::{Builder, Credentials, Region},
presigning::PresigningConfig,
Client,
};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let creds = Credentials::new(
std::env::var("WASABI_ACCESS_KEY")?,
std::env::var("WASABI_SECRET_KEY")?,
None, None, "wasabi",
);
let config = Builder::new()
.behavior_version(BehaviorVersion::latest())
.region(Region::new("eu-central-1"))
.endpoint_url("https://s3.eu-central-1.wasabisys.com")
.credentials_provider(creds)
.build();
let client = Client::from_conf(config);
let presigning_config = PresigningConfig::expires_in(Duration::from_secs(300))?;
let presigned = client
.put_object()
.bucket("my-bucket")
.key("invoices/inv-001.pdf")
.content_type("application/pdf")
.presigned(presigning_config)
.await?;
println!("{}", presigned.uri());
Ok(())
}
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;
import java.net.URI;
import java.time.Duration;
public class Main {
public static void main(String[] args) {
try (S3Presigner presigner = S3Presigner.builder()
.region(Region.of("eu-central-1"))
.endpointOverride(URI.create("https://s3.eu-central-1.wasabisys.com"))
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create(
System.getenv("WASABI_ACCESS_KEY"),
System.getenv("WASABI_SECRET_KEY")
)
))
.build()) {
PutObjectRequest objectRequest = PutObjectRequest.builder()
.bucket("my-bucket")
.key("invoices/inv-001.pdf")
.contentType("application/pdf")
.build();
PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(5))
.putObjectRequest(objectRequest)
.build();
System.out.println(presigner.presignPutObject(presignRequest).url());
}
}
}
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.Runtime;
// NuGet: AWSSDK.S3
var credentials = new BasicAWSCredentials(
Environment.GetEnvironmentVariable("WASABI_ACCESS_KEY"),
Environment.GetEnvironmentVariable("WASABI_SECRET_KEY")
);
var config = new AmazonS3Config
{
ServiceURL = "https://s3.eu-central-1.wasabisys.com",
ForcePathStyle = true,
};
var s3 = new AmazonS3Client(credentials, config);
var request = new GetPreSignedUrlRequest
{
BucketName = "my-bucket",
Key = "invoices/inv-001.pdf",
Verb = HttpVerb.PUT,
ContentType = "application/pdf",
Expires = DateTime.UtcNow.AddMinutes(5),
};
string presignedUrl = s3.GetPreSignedURL(request);
Console.WriteLine(presignedUrl);
PolyDoc API request
Pass the presigned URL to PolyDoc. The converted document is uploaded directly to your Wasabi bucket. The response is JSON containing the permanent object URL.
const response = await fetch('https://api.polydoc.tech/pdf/convert', {
method: 'POST',
headers: {
'Authorization': 'Bearer <YOUR_API_KEY>',
'Content-Type': 'application/json',
'X-Sandbox': 'true',
},
body: JSON.stringify({
source: '<html><body><h1>Hello</h1></body></html>',
cloudStorage: { presignedUrl },
}),
});
const result = await response.json();
console.log(result.data.url);
// → https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf
import requests
headers = {
'Authorization': 'Bearer <YOUR_API_KEY>',
'Content-Type': 'application/json',
'X-Sandbox': 'true',
}
data = {
'source': '<html><body><h1>Hello</h1></body></html>',
'cloudStorage': {'presignedUrl': presigned_url},
}
response = requests.post(
'https://api.polydoc.tech/pdf/convert',
headers=headers,
json=data,
)
result = response.json()
print(result['data']['url'])
# → https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://api.polydoc.tech/pdf/convert')
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer <YOUR_API_KEY>'
request['Content-Type'] = 'application/json'
request['X-Sandbox'] = 'true'
request.body = JSON.dump({
'source' => '<html><body><h1>Hello</h1></body></html>',
'cloudStorage' => { 'presignedUrl' => presigned_url },
})
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
result = JSON.parse(response.body)
puts result['data']['url']
# → https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
payload := map[string]interface{}{
"source": "<html><body><h1>Hello</h1></body></html>",
"cloudStorage": map[string]string{
"presignedUrl": presignedUrl,
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.polydoc.tech/pdf/convert", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer <YOUR_API_KEY>")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Sandbox", "true")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result["data"].(map[string]interface{})["url"])
// → https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf
}
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.polydoc.tech/pdf/convert');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'source' => '<html><body><h1>Hello</h1></body></html>',
'cloudStorage' => ['presignedUrl' => $presignedUrl],
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer <YOUR_API_KEY>',
'Content-Type: application/json',
'X-Sandbox: true',
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
echo $result['data']['url'];
// → https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf
use reqwest::Client;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let res = client
.post("https://api.polydoc.tech/pdf/convert")
.header("Authorization", "Bearer <YOUR_API_KEY>")
.header("X-Sandbox", "true")
.json(&json!({
"source": "<html><body><h1>Hello</h1></body></html>",
"cloudStorage": { "presignedUrl": presigned_url }
}))
.send()
.await?;
let result: serde_json::Value = res.json().await?;
println!("{}", result["data"]["url"]);
// → https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf
Ok(())
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
ObjectMapper mapper = new ObjectMapper();
String body = mapper.writeValueAsString(Map.of(
"source", "<html><body><h1>Hello</h1></body></html>",
"cloudStorage", Map.of("presignedUrl", presignedUrl)
));
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://api.polydoc.tech/pdf/convert"))
.header("Authorization", "Bearer <YOUR_API_KEY>")
.header("Content-Type", "application/json")
.header("X-Sandbox", "true")
.POST(BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString()
);
var result = mapper.readValue(response.body(), Map.class);
System.out.println(((Map) result.get("data")).get("url"));
// → https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf
}
}
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "<YOUR_API_KEY>");
client.DefaultRequestHeaders.Add("X-Sandbox", "true");
var payload = JsonSerializer.Serialize(new {
source = "<html><body><h1>Hello</h1></body></html>",
cloudStorage = new { presignedUrl }
});
var content = new StringContent(payload, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.polydoc.tech/pdf/convert", content);
var json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
Console.WriteLine(doc.RootElement.GetProperty("data").GetProperty("url").GetString());
// → https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf
curl --location \
--request POST 'https://api.polydoc.tech/pdf/convert' \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
--header 'Content-Type: application/json' \
--header 'X-Sandbox: true' \
--data-raw '{
"source": "<html><body><h1>Hello</h1></body></html>",
"cloudStorage": {
"presignedUrl": "<PRESIGNED_URL>"
}
}'
# Response:
# {
# "success": true,
# "data": {
# "url": "https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf"
# }
# }
Response
On success, PolyDoc returns the permanent object URL.
{
"success": true,
"message": "PDF uploaded to cloud storage.",
"data": {
"url": "https://my-bucket.s3.eu-central-1.wasabisys.com/invoices/inv-001.pdf"
}
}