Delivery keys
A delivery key is a publishable credential (cvly_pub_…) that identifies the workspace whose files a URL is allowed to fetch. Embed it in HTML; never confuse it with a regular server-side API key.
Delivery keys (cvly_pub_…) are designed to be public. Regular API keys (cvly_… without _pub_) are not — they can upload, convert, delete, and manage your workspace. Never put a regular API key behind NEXT_PUBLIC_* or anywhere it ships to the browser.
Manage delivery keys
| Method | Endpoint | Use |
|---|
GET | /api/delivery-keys | List your delivery keys (prefixes, aliases, last used timestamps). |
POST | /api/delivery-keys | Create a delivery key. Body: { "name": "Marketing site", "alias": "marketing" }. The full token is returned once — store it where your site can read it. |
GET | /api/delivery-keys/alias?alias=marketing | Check whether an alias is available before creating a key. |
DELETE | /api/delivery-keys/{id} | Revoke a delivery key. Any URL signed with it stops resolving immediately. |
curl -X POST "https://convertly.sh/api/delivery-keys" \
-H "Authorization: Bearer $CONVERTLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Marketing site", "alias": "marketing" }'
# {
# "key": { "id": "...", "name": "Marketing site", "key_prefix": "cvly_pub_abc...", "delivery_alias": "marketing" },
# "token": "cvly_pub_abc1234..."
# }
You can also manage delivery keys visually from Settings → Image CDN → Delivery keys.
Delivery aliases
A delivery alias is an optional short prefix (marketing, site, products) that replaces the long cvly_pub_… token in public URLs:
https://cdn.convertly.sh/marketing/{fileId}?w=1200&format=auto
Aliases are:
- Set at key creation time (3–63 chars, lowercase,
[a-z0-9_-], globally unique)
- Checked with
GET /api/delivery-keys/alias?alias=… before you commit
- Compatible with custom domains, signed URLs, and CDN slugs
See URL structure for how aliases compose with hostnames and file identifiers.
Rotating a delivery key
Delivery keys can be rotated freely. Create a new key, update your application to use the new token, then revoke the old one. The underlying files stay put — the only effect is that all URLs using the old key prefix stop resolving and any cached responses are no longer reachable via that path.
Origin sources
Required before origin-backed CDN URLs work. Any URL containing /o/{slug}/ tells Convertly to fetch from a source you registered here. The SDK and Next.js loader only rewrite paths to that shape — they do not create origins for you.
Typical setups:
| Use case | Slug example | Base URL example |
|---|
| Deployed Next.js / static site | site | https://example.com |
| Public asset bucket or CDN | products | https://assets.example.com |
| WordPress uploads folder | wp-uploads | https://blog.example.com/wp-content/uploads |
Each external host must be registered separately. Convertly does not offer open per-request remote URL fetch (unlike some competitors); origins are workspace-scoped for security.
Add sources from Image CDN → Sources in the dashboard (or POST /api/cdn-origins).
| Mode | When to use | What Convertly stores |
|---|
| Public HTTPS | Bucket or site already has a public read URL | Origin URL + optional path prefix |
| Private bucket | S3, R2, GCS, or Azure without public access | Encrypted read credentials + bucket metadata |
Private credentials are encrypted at rest and never returned by the API. Rotate credentials by updating the origin source with new keys.
For public origins, Convertly does not fetch localhost, 127.0.0.1, private IP ranges, or non-HTTPS URLs. That keeps the CDN from becoming a private-network proxy.
curl -X POST "https://convertly.sh/api/cdn-origins" \
-H "Authorization: Bearer $CONVERTLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Product images",
"slug": "products",
"sourceType": "r2",
"authMode": "private",
"baseUrl": "https://my-bucket.example.r2.cloudflarestorage.com",
"pathPrefix": "catalog",
"credentials": {
"kind": "s3",
"accessKeyId": "…",
"secretAccessKey": "…",
"bucket": "my-bucket",
"endpoint": "https://…r2.cloudflarestorage.com"
}
}'
Purging the edge cache
When you change a file’s underlying bytes in place (rare — see Replacing a file for the recommended pattern) and need cached URLs evicted immediately across all edge locations, call the purge API:
curl -X POST "https://convertly.sh/api/cdn-purge" \
-H "Authorization: Bearer $CONVERTLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"urls": [
"https://cdn.convertly.sh/marketing/{fileId}?w=1200",
"https://cdn.convertly.sh/cvly_pub_.../{fileId}?w=600"
]
}'
# { "ok": true, "purged": [ "...", "..." ] }
Notes:
- Use your server-side
cvly_… API key, not a delivery key. Purging is a workspace mutation.
- Pass the URLs you actually embedded — Cloudflare matches exactly, so
?w=1200 and ?w=600 are separate cache entries that each need their own purge.
- Up to 30 URLs per request. Send multiple requests for more.
- Purges complete in seconds globally.
If purge isn’t configured on your Convertly instance (you’ll get a 503 with a clear message), use the file-id versioning pattern below instead.
Replacing a file
URLs are immutable for a year by design — that’s what enables high cache hit ratios. Practical implications when you need to update an image:
- Upload the new version as a separate file (which gets its own
fileId), then update your markup to point at the new id. The old URL keeps serving the old bytes from CDN cache until it eventually expires, and the new one is fresh from day one.
- Overwriting a file in place will not refresh cached URLs. Caches that already have the old bytes will keep serving them until edge eviction or the year-long TTL expires. Use the purge API if you need immediate invalidation.
For most workflows, treating uploaded files as immutable assets and rotating the file id for updates is simpler and aligns with how every URL-transform CDN expects to be used.
Security model
- Delivery keys are workspace-scoped and read-only. Revoking one stops all URLs signed with it immediately.
- File IDs are UUIDs by default — they are not enumerable, but anyone who scrapes your HTML can re-request the same file at any size. Set an optional CDN slug when you want a readable path segment instead.
- For gated content, use Signed URLs. A signed URL covers the delivery key, file id, and every parameter — any tampering invalidates the signature and returns
403.
- The endpoint never reveals file lists, account identifiers, or any internal storage path.
- Delivery keys can be rotated. New key → new URL prefix → fresh cache, but the underlying files stay put.
Local development
Public origin sources must be reachable over public HTTPS. Convertly does not fetch localhost, 127.0.0.1, or private IP ranges through the public-URL path.
Private origin sources do not require a public bucket URL — credentials are used server-side only.
For framework loaders, use a local passthrough option while running your app locally so public-folder assets render from your dev server. Those local requests are not transformed by Convertly. To test the real optimized path before production, use a public preview deployment as the origin source, or temporarily expose your local server through an HTTPS tunnel and point the origin source at that tunnel URL.