Skip to main content

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

MethodEndpointUse
GET/api/delivery-keysList your delivery keys (prefixes, aliases, last used timestamps).
POST/api/delivery-keysCreate 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=marketingCheck 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 caseSlug exampleBase URL example
Deployed Next.js / static sitesitehttps://example.com
Public asset bucket or CDNproductshttps://assets.example.com
WordPress uploads folderwp-uploadshttps://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).
ModeWhen to useWhat Convertly stores
Public HTTPSBucket or site already has a public read URLOrigin URL + optional path prefix
Private bucketS3, R2, GCS, or Azure without public accessEncrypted 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.