# Save files to your own S3 bucket

> Learn how to save generated images and PDFs to your own S3-compatible bucket with s3Config.

Canonical: https://bannerify.co/docs/integrations/storage-and-notifications

By default, Bannerify saves a stored file on its CDN and returns a link on `images.bannerify.co`. Add an `s3Config` object to the request, and Bannerify writes the file to your bucket and returns the link to that copy. Use it when the files must live in your own storage or behind your own domain. Custom S3 storage is part of the Scale and Enterprise plans.

## Prerequisites

- A workspace on the Scale or Enterprise [plan](https://bannerify.co/docs/account/billing). A request with `s3Config` from a workspace on the Free or Automate plan fails with [`FORBIDDEN`](https://bannerify.co/docs/api-reference/errors/code/FORBIDDEN) and does not count as a generation.
- An S3-compatible bucket and an access key that can upload objects to it. Bannerify only uploads files. It does not read or delete anything in the bucket.
- A Bannerify [API key](https://bannerify.co/docs/api-reference/authentication#create-an-api-key) and a template.

## Save a file to your bucket

1. Add `s3Config` to the body of a `createStoredImage` or `createStoredPdf` request:

```bash
curl --request POST \
  --url https://api.bannerify.co/v1/templates/createStoredImage \
  --header 'Content-Type: application/json' \
  --data '{
    "apiKey": "YOUR_API_KEY",
    "templateId": "tpl_xxx",
    "modifications": [
      { "name": "headline", "text": "Saved to my bucket" }
    ],
    "s3Config": {
      "endPoint": "s3.amazonaws.com",
      "region": "us-east-1",
      "bucket": "my-bannerify-renders",
      "accessKey": "YOUR_ACCESS_KEY",
      "secretKey": "YOUR_SECRET_KEY"
    }
  }'
```

2. Read the response. The `url` points to the file in your bucket:

```json
{
  "url": "https://my-bannerify-renders.s3.amazonaws.com/0b3c1c1e-5d6f-4c52-9e0a-8f6a4c0f2a11.png"
}
```

Send this request from your server. The body holds your API key and your secret key, so keep it out of browser code.

Only the two stored endpoints use `s3Config`. The `createImage`, `createPdf`, and `signedurl` endpoints do not save files.

## s3Config fields

| Field | Required | Description |
| --- | --- | --- |
| `endPoint` | Yes | The S3 endpoint host without the protocol, such as `s3.amazonaws.com` |
| `region` | Yes | The region of the bucket, such as `us-east-1` |
| `bucket` | Yes | The name of the bucket |
| `accessKey` | Yes | The access key |
| `secretKey` | Yes | The secret key |
| `port` | No | The port of the endpoint. The default is `443`. Set it when you turn `useSSL` off |
| `useSSL` | No | Connect over HTTPS. The default is `true` |
| `pathStyle` | No | Put the bucket name in the URL path (`https://endpoint/bucket/file`) instead of the host name (`https://bucket.endpoint/file`). The default is `false` |
| `customUrl` | No | A template for the returned link. Bannerify replaces `{key}` with the file name. This changes only the link in the response, and the upload still goes to `endPoint` |

A missing required field fails with [`BAD_REQUEST`](https://bannerify.co/docs/api-reference/errors/code/BAD_REQUEST).

## Where the file goes

- Bannerify writes the file to the root of the bucket. The name is a random id plus an extension: `.png`, `.jpg` for JPEG, `.webp`, or `.pdf`. You cannot choose a folder or a name.
- The file lives only in your bucket. Bannerify does not keep a copy on its CDN.
- The returned link is not signed. It works only when whoever opens it can read the object, so make the object public or set `customUrl` to a public address.

## Use Cloudflare R2

Cloudflare R2 uses the same fields. Set `endPoint` to `ACCOUNT_ID.r2.cloudflarestorage.com` with your account id, and set `region` to `auto`. R2 serves public files from a custom domain, so set `customUrl` to that domain:

```json
{
  "endPoint": "ACCOUNT_ID.r2.cloudflarestorage.com",
  "region": "auto",
  "bucket": "my-bannerify-renders",
  "accessKey": "YOUR_ACCESS_KEY",
  "secretKey": "YOUR_SECRET_KEY",
  "customUrl": "https://files.example.com/{key}"
}
```

## Use an SDK or a no-code tool

The JavaScript SDK accepts `s3Config` in `createStoredImage`. See [Create images and PDFs](https://bannerify.co/docs/sdk/js/apis/create-image#create-a-stored-image). The Python and PHP SDKs cannot send `s3Config`, the Go SDK has no stored image method, and no SDK wraps `createStoredPdf`. Call the REST endpoint from those languages.

The Zapier, n8n, and Pipedream actions do not send `s3Config`. To save files to your bucket from a workflow, call the REST endpoint from an HTTP request step in the tool.

## Handle upload errors

When the upload to your bucket fails, the request fails with `INTERNAL_SERVER_ERROR` and the message `Failed to upload image to custom S3 storage`. For a PDF the message is `Failed to upload PDF to custom S3 storage`. Check the endpoint, the region, the bucket name, and the keys. [`INTERNAL_SERVER_ERROR`](https://bannerify.co/docs/api-reference/errors/code/INTERNAL_SERVER_ERROR) explains how to handle the code.

## Send the link to other apps

To send a file to Google Drive, Dropbox, or Slack, add a step after the Bannerify action in [Zapier](https://bannerify.co/docs/integrations/zapier), [n8n](https://bannerify.co/docs/integrations/n8n), or [Pipedream](https://bannerify.co/docs/integrations/pipedream). That step uploads the file from its `url` or posts the link in a message.

## Related

- [Previous: Embed the editor in your app](https://bannerify.co/docs/integrations/embed-editor)
- [Next: Connect an MCP client](https://bannerify.co/docs/mcp/overview)
- [Documentation index](https://bannerify.co/docs/llms.txt)
