Upload to S3
By default, generated PDFs are stored temporarily on our CDN and accessed via signed URLs. With S3 integration, PDFs go directly to your own bucket instead.
This is useful when you want:
- Convenience — PDFs land directly in your existing storage, no extra step to download and re-upload
- Privacy — we never store your documents, not even temporarily
- Control — your bucket, your retention policy, your access rules
Supported providers
Any S3-compatible storage works:
| Provider | Endpoint URL |
|---|---|
| Amazon S3 | https://s3.amazonaws.com or https://s3.{region}.amazonaws.com |
| Cloudflare R2 | https://{account_id}.r2.cloudflarestorage.com |
| DigitalOcean Spaces | https://{region}.digitaloceanspaces.com |
| MinIO | Your MinIO endpoint URL |
| Backblaze B2 | https://s3.{region}.backblazeb2.com |
| Wasabi | https://s3.{region}.wasabisys.com |
Setup
1. Create a bucket
Create a bucket for your generated PDFs. A dedicated bucket (or at least a dedicated prefix) keeps things organized.
2. Create access credentials
Create an IAM user or access key with minimal permissions. We only need to upload files — nothing else.
Minimal policy (upload only):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}With connection testing:
To use the “Test Connection” button in the dashboard, add ListBucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": "arn:aws:s3:::your-bucket-name/*"
},
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": "arn:aws:s3:::your-bucket-name"
}
]
}Why least privilege? If these credentials were ever exposed, the damage is limited — they can only write to one bucket, nothing else. Never use your root AWS credentials.
3. Configure in dashboard
Go to Dashboard > Integrations > S3 Storage and enter your credentials:
- Endpoint URL — must be HTTPS
- Access Key ID
- Secret Access Key — stored encrypted, never exposed in API responses
- Bucket Name
- Default Prefix — optional, e.g.
generated/pdfs/
Click Test Connection to verify.
Using S3 in API calls
Add store_s3: true to your PDF generation request:
curl -X POST https://api.pdftemplateapi.com/v1/pdf/create \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template_id": "HMQywVpZxqAM",
"data": {
"customer_name": "Acme Corp",
"invoice_number": "INV-001"
},
"store_s3": true,
"filename": "invoice-001"
}'Response:
{
"s3_bucket": "my-pdf-bucket",
"s3_key": "generated/pdfs/invoice-001.pdf",
"filename": "invoice-001.pdf",
"credits_remaining": 99
}Optional parameters
| Parameter | Description |
|---|---|
s3_filepath | Override the default prefix for this request |
s3_bucket | Use a different bucket for this request |
filename | Custom filename (without .pdf extension) |
Example with custom path:
{
"template_id": "HMQywVpZxqAM",
"data": { "..." },
"store_s3": true,
"s3_filepath": "customers/acme/invoices/",
"filename": "INV-2026-001"
}Result: customers/acme/invoices/INV-2026-001.pdf
Use cases
Archival and compliance — Keep invoices, contracts, or receipts in your own storage with your own retention policy. Useful for GDPR, HIPAA, SOC 2, or just internal policies.
Integration with existing workflows — If your app already reads from S3 (serving files, processing documents, triggering Lambda functions), generated PDFs slot right in.
Multi-region or data sovereignty — Store documents in a specific AWS region or country to meet legal requirements.
CDN integration — Put your bucket behind CloudFront, Cloudflare, or another CDN for fast global delivery with your own domain.
Security
Your credentials are protected:
- Encrypted at rest — secret keys use Fernet encryption
- Never exposed — API responses only show masked keys (e.g.,
wJal...EKEY) - User isolation — each user can only access their own configuration
- HTTPS required — all endpoint URLs must use HTTPS
API reference
For complete endpoint documentation, see S3 Storage Integration in the API Reference.