Storage destinations API
Configure where HCTI saves rendered files. Your bucket must already exist, and your plan must support storage destinations. Compare plans to add this feature. See the storage guide for provider permissions and image storage behavior.
Operations
Reads, including the AWS external-ID operation, share 100 requests/minute. Writes share 20 requests/minute, per organization across REST and MCP. See rate limits and the interactive API reference.
Create a new storage destination
/v1/storage-destinations - Permission required
storage_destinations:create_update- MCP tool
create_storage_destination
List storage destinations
/v1/storage-destinations - Permission required
storage_destinations:read- MCP tool
list_storage_destinations
Retrieve a storage destination
/v1/storage-destinations/{id} - Permission required
storage_destinations:read- MCP tool
get_storage_destination
Update a storage destination
/v1/storage-destinations/{id} - Permission required
storage_destinations:create_update- MCP tool
update_storage_destination
Delete a storage destination
/v1/storage-destinations/{id} - Permission required
storage_destinations:delete- MCP tool
delete_storage_destination
Get the AWS storage external ID
/v1/storage-destinations/aws-external-id - Permission required
storage_destinations:create_update- MCP tool
get_aws_storage_external_id
Configure Amazon S3
First retrieve your organization’s external ID:
curl 'https://hcti.io/v1/storage-destinations/aws-external-id' \
--user "$HCTI_API_ID:$HCTI_API_KEY"
The response is an object with external_id. This operation requires create/update permission. It does not require a destination ID.
Use that value as sts:ExternalId in the IAM role trust policy described in the Amazon S3 guide. Configure the role’s bucket permissions, then create the destination:
curl 'https://hcti.io/v1/storage-destinations' \
--user "$HCTI_API_ID:$HCTI_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"name": "Production images",
"disabled": false,
"hcti_storage_disabled": false,
"connection_info": {
"provider": "aws_s3",
"bucket": "your-image-bucket",
"key_prefix": "renders/",
"region": "us-east-1",
"role_arn": "arn:aws:iam::123456789012:role/HctiImageStorage"
}
}'
Replace the example bucket and role with your configured AWS resources. HCTI tests a write before enabling the destination.
Request fields
| Field | Description |
|---|---|
name | Required, 3–255 characters. |
disabled | Defaults to false. Set true to save a disabled configuration. Responses use enabled. |
hcti_storage_disabled | Defaults to false. If true, rendered files saved here have no public HCTI URL and are excluded from HCTI storage/CDN caching. |
connection_info | Required provider-specific object, with provider and bucket. Optional key_prefix selects a prefix within the bucket. |
Provider settings
All providers require bucket. All except Amazon S3 use access_key_id and secret_access_key; Amazon S3 uses an IAM role instead. On update, access-key providers can use retain_secret_access_key: true to keep the existing secret explicitly.
provider | Additional connection fields | Setup guide |
|---|---|---|
aws_s3 | Required region, role_arn | Amazon S3 |
cloudflare_r2 | Required cloudflare_account_id; optional cloudflare_jurisdiction (eu, fedramp, or null/default) | Cloudflare R2 |
backblaze_b2 | Required region, such as us-west-004 | Backblaze B2 |
digitalocean_spaces | Required region, such as nyc3 | DigitalOcean Spaces |
wasabi | Required region, such as us-east-1 | Wasabi |
google_cloud_storage | HMAC access_key_id beginning with GOOG and its secret | Google Cloud Storage |
other_s3_compatible | Required public HTTPS endpoint; optional region (default us-east-1) and force_path_style (default true) | Other S3-compatible providers |
Use a provider’s supported region value from the API reference. Custom endpoints must not contain a path, query, fragment, or credentials. Do not send a generic custom endpoint in place of the provider-specific fields.
Responses, listing, and retrieval
Creates, updates, and gets return 200 OK with:
| Field | Description |
|---|---|
id | Destination identifier used in management requests and as storage_destination_id when creating images. |
name | Display name of the destination. |
enabled | Whether the destination is enabled. |
hcti_storage_disabled | When true, files saved here are excluded from HCTI storage and CDN caching and have no public HCTI image URL. |
connection_info | Provider connection details without the secret access key. |
last_tested_at | UTC timestamp of the most recent test, or null. |
last_test_succeeded | Whether that write test succeeded, or null if untested. |
last_test_error | Sanitized test error, or null. |
created_at | UTC timestamp when the destination was created. |
updated_at | UTC timestamp when the destination was last updated. |
- List destinations:
GET /v1/storage-destinationsreturns destinations newest first, including disabled destinations. - Page size: Set
countfrom 1 to 100. The default is 10. - Next page: Pass the response’s
pagination.next_page_startaspage_startin the next request. Stop when the returned cursor isnull. - Retrieve one destination: Use
GET /v1/storage-destinations/{id}.
See pagination for the shared response format.
Updates and connection tests
Send POST /v1/storage-destinations/{id} with the complete replacement configuration. Omitted optional settings clear or reset. For access-key providers, choose explicitly whether to retain or replace the secret:
- Keep the secret: Set
connection_info.retain_secret_access_key: true, keep the provider and access key ID unchanged, and omitsecret_access_keyor set it to null. Existing credentials are required. - Replace the secret: Supply
connection_info.secret_access_keyand omitretain_secret_access_keyor set it to false. Creating a destination or changing its provider or access key ID requires a supplied secret. - Missing or conflicting instructions: An omitted, null, or false retention flag requires a supplied secret, including when disabling the destination. Combining
retain_secret_access_key: truewith a supplied secret returns400. Empty or whitespace-only storage secrets are invalid.
For example, this complete R2 update retains the existing secret. Replace the destination ID, account ID, access key ID, and other settings with those of your destination:
curl "https://hcti.io/v1/storage-destinations/$DESTINATION_ID" \
--user "$HCTI_API_ID:$HCTI_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"name": "Production images",
"disabled": false,
"hcti_storage_disabled": false,
"connection_info": {
"provider": "cloudflare_r2",
"bucket": "your-image-bucket",
"key_prefix": "renders/",
"cloudflare_account_id": "0123456789abcdef0123456789abcdef",
"access_key_id": "your-existing-access-key-id",
"retain_secret_access_key": true
}
}'
Amazon S3 uses an IAM role, so these access-key retention fields do not apply. Retention flags are request-only and are not returned in connection_info.
Connection tests
Creation tests a write to the bucket. Changed connection settings and re-enabling a destination also trigger testing; metadata-only changes do not require a test. HCTI attempts to delete its test object, but cleanup failure does not make the write test fail. Test objects may remain under <key-prefix>/.hcti/connection-tests/ without delete permission.
An enabled request is not saved if the test fails. An explicitly disabled configuration can be saved with a failed test result. Inspect last_test_succeeded and last_test_error; a successful write test does not verify read permissions or guarantee future connectivity.
After a plan downgrade removes storage-destination support, updates can only disable the destination; other submitted changes are ignored.
Delete a destination
DELETE /v1/storage-destinations/{id} returns 204 No Content on success. Repeated deletion succeeds. It removes the configuration and its stored credentials, but does not delete the bucket or objects already stored there. Existing images retain their destination reference, and storage retries depending on a disabled or deleted destination fail.
Use the destination for images
Pass the returned id as storage_destination_id on an image request or template. Creating an image uses image permissions; managing destination configuration uses the permissions above. Authenticated PUT /v1/store/{id} requires images:store.
MCP
Create accepts content with the request fields above. Update takes id and content; get/delete take id; list takes count and page_start. get_aws_storage_external_id takes no arguments.
For example: “Use HCTI to get my AWS storage external ID so I can configure an IAM role, then list my storage destinations.” Approve both storage_destinations:create_update and storage_destinations:read for that workflow. See MCP tools and authorization.
Need help?
Talk to a human. Please email us support@htmlcsstoimage.com with any questions and we’ll gladly help you get started.