Docs
Upload an image once, then request the size you need by adding it to the file name. This page covers URL rules, sizes and the API.
Getting started
The dashboard is currently in Turkish.
- Create an account, then create a key in the API keys (API anahtarları) section of the dashboard. Keys start with
tcdn_and are shown only once. - In the Sizes (Ölçüler) section, define the sizes your site uses, for example 400×400 named
kart. The name is up to you;kartis Turkish for "card". - Upload the image, then use its URL with the size name.
curl -X PUT \
-H "Authorization: Bearer tcdn_..." \
--data-binary @kapak.jpg \
https://api.turkcdn.com/v1/images/urun/kapak.jpg
# pip install requests import requests TOKEN = "tcdn_..." # Dashboard → API keys API = "https://api.turkcdn.com/v1" headers = {"Authorization": f"Bearer {TOKEN}"} with open("kapak.jpg", "rb") as f: r = requests.put(f"{API}/images/urun/kapak.jpg", headers=headers, data=f) r.raise_for_status() print(r.json()["url"])
<img src="https://cdn.turkcdn.com/magazam/urun/kapak_kart.webp" width="400" height="400" alt="Product">
Image URLs
Every image URL has the form https://cdn.turkcdn.com/{account}/{path}. {account} is the account name shown in the dashboard, and {path} is the path you gave when uploading. Size and format are read from the file name; no query parameters or SDK needed.
| Requested URL | Result |
|---|---|
urun/kapak.jpg | The original file |
urun/kapak.webp | WebP at the original size |
urun/kapak_kart.avif | kart template, AVIF |
urun/kapak_kart_s.webp | kart size, fitted without cropping. Command order doesn't matter: _s_kart works too. |
urun/kapak_400x400.jpg | Generated if 400×400 is in your allowed sizes |
urun/kapak_w400.webp | Width 400, height from the aspect ratio; _h400 does the reverse. This size must also be in your allowed sizes. |
urun/kapak_akart.webp | akart template with all its settings: size, crop, effects, viewer |
urun/kapak_akart_300x250.webp | akart template at 300×250. Returns 404 if 300×250 is not in your allowed sizes. |
urun/kapak_th_kart.webp | Legacy format, still supported |
Each _ at the end of the file name starts a command, and command order doesn't matter. File names that contain underscores work too: the full name is looked up first, and if it isn't found, the trailing parts are read as commands. A URL can contain at most one template name and one size. You can't use _th_ in a file name, because it is the legacy format's separator.
Origin pull (web proxy)
If your images already live on a website, you don't need to upload any of them. Set your site as the zone's origin, then change only the domain in the image URLs on your pages. The first time an image that isn't in the zone is requested, it is fetched from the origin, saved to your zone, and the requested size is generated. Later requests are served straight from the CDN.
Setup
- In the dashboard, on the Zones (Alanlar) page, click Origin: Add (Kaynak: Ekle) next to your zone.
- Enter your site's URL:
https://mysite.com. If your images are in a folder, you can include the folder too:https://mysite.com/uploads. - In the image URLs on your pages, replace
https://mysite.comwithhttps://cdn.turkcdn.com/{zone}and add the size you want to the file name.
<!-- Before --> <img src="https://mysite.com/urun/ayakkabi.jpg"> <!-- After: kart template, as WebP --> <img src="https://cdn.turkcdn.com/magazam/urun/ayakkabi_kart.webp">
Which file is fetched?
Commands and the extension are removed from the URL, and the remaining path is appended to the origin:
| Requested URL | Fetched from origin |
|---|---|
urun/ayakkabi.jpg | mysite.com/urun/ayakkabi.jpg |
urun/ayakkabi_300x250.jpg | mysite.com/urun/ayakkabi.jpg |
urun/ayakkabi_kart.webp | ayakkabi.webp, if not found .jpg, then .png |
Spaces and non-ASCII characters (such as Turkish letters) are encoded in the URL automatically. If the origin is https://mysite.com/uploads, the same URLs are looked up as https://mysite.com/uploads/urun/…. If you've connected your own domain, the same works there too: https://img.mysite.com/urun/ayakkabi_kart.webp.
Things to know
- The first request is a bit slower: the image is downloaded from the origin and processed. After that it comes from the CDN.
- Updating images: TurkCDN doesn't check the origin again. If you change an image at the origin, delete it in the dashboard or through the API (
DELETE /images/{path}); the new version is fetched on the next request. - Missing files: a file that isn't found at the origin returns 404 and isn't requested again for 10 minutes. Changing the origin URL resets this wait.
- The origin must be reachable: requests use the user agent
TurkCDN/1 (+https://turkcdn.com)and give up if there is no response within 10 seconds. Redirects (301, 302) are not followed; the URL must serve the image directly. If your site has hotlink or bot protection, allow this user agent. - Limits: the upload rules apply: up to 20 MB, JPG, PNG, WebP or GIF. Fetched images count toward your plan's image count and storage.
- Security: only publicly reachable addresses are contacted; internal network and local addresses are blocked.
Sizes and templates
The Sizes tab in the dashboard has two separate lists:
- Allowed sizes: An unnamed list of width × height values. You request them in the URL by dimensions (
_300x250,_w400,_h400), and you can use them to override a template's size. They are cropped from the center. - Templates: A name is required. A template stores the default size, mode, crop anchor, quality, styling commands and viewer together; you request it in the URL by name (
_akart).
In the API both use the /presets endpoint: with name it's a template, without it it's a size. Sizes can't use effects or viewer.
| Field | Value |
|---|---|
name | Required for templates. 1-32 characters; lowercase letters, digits and hyphens. Can't look like a size, such as 120x60 or w400. |
width, height | 0 to 4000 pixels; if one is 0 it is calculated from the aspect ratio, but both can't be 0 |
mode | cover (default): fills the area and crops the overflow. contain: fits while keeping the aspect ratio, never upscales. |
anchor | Crop anchor: tl, t, tr, l, c (default), r, bl, b, br |
quality | 1 to 100, default 82 |
image_id | If set, the preset applies only to that image |
effects | Templates only. Styling commands, written as in the URL: rounded-lg_border-2-eeeeee |
viewer | Templates only. o-on, z-on or o-on_z-on; see Lightbox and zoom |
When you change a preset, the copies generated from it are deleted and regenerated with the new settings on the next request.
Styling commands
You can save corners, borders and similar settings in a preset, or add them directly to the URL. They also work without a size; in that case they are applied at the image's own size.
| Command | Turkish alias | What it does |
|---|---|---|
_rounded-sm, _rounded, _rounded-md, _rounded-lg, _rounded-xl | _yuvarlak-az, _yuvarlak, _yuvarlak-orta, _yuvarlak-buyuk, _yuvarlak-cok | Rounds the corners, from smallest to largest |
_rounded-full | _yuvarlak-tam | Corner radius of half the short side: a pill on a rectangle, a circle on a square. Doesn't crop. |
_circle | _daire | Crops a square from the center and makes it a circle |
_border, _border-thick | _cerceve, _cerceve-kalin | Thin or thick inner border; the image size doesn't change. White by default; you can add a color: _border-1d3557, _border-thick-eee |
_bg-f5f5f5 | _zemin-f5f5f5 | Fills the empty space left when fitting with _s, and transparent corners in JPG, with this color |
_p-sm, _p-md, _p-lg | _bosluk-az, _bosluk-orta, _bosluk-cok | The size stays the same; the image is inset and surrounded by transparent space. You can color it with _bg-; in JPG it is white. In pixels: _p-24 |
_grayscale | _gri | Black and white |
_blur-low, _blur, _blur-high | _bulanik-az, _bulanik, _bulanik-cok | Light, medium or strong blur |
_shadow-low, _shadow, _shadow-high | _golge-az, _golge, _golge-cok | Light, normal or strong shadow; the size grows because space is added around the edges |
_opacity-50 | _opaklik-50 | How visible the image is, in percent, 1-99; everything, including the shadow, becomes transparent. JPG has no transparency, so it blends into white; request .png, .webp or .avif |
_logo | _filigran | Applies the zone's watermark; does nothing if there is no watermark |
Levels scale with the image size, so they look the same on a 200 px and a 2000 px image. To set pixels, use a number: _rounded-16 (1-500), _border-2 and _border-2-eeeeee (1-50), _blur-8 (1-50). The Turkish aliases work the same way: _yuvarlak-16, _cerceve-2-eeeeee, _bulanik-8.
English and Turkish commands are aliases of each other and produce the same copy. You can't write the same command in both languages: _gri_grayscale is invalid.
Commands can be written in any order and combined: urun/kapak_kart_rounded-lg_border.webp, ekip/ayse_circle.png, banner_grayscale_blur-low.jpg. A URL can have at most 6 commands, and each command can appear only once. Colors are 3- or 6-digit lowercase hex.
To use a combination you need often under your own name, save it to a preset: for example, make a preset named kapak ("cover") with rounded-lg_shadow, then write _kapak in the URL. If the same command is in both the preset and the URL, the URL's value is used. For transparent corners, request .webp, .avif or .png; JPG has no transparency, so the corners are filled with white or the _bg color.
Lightbox and zoom
Add this line to your site once:
<script src="https://cdn.turkcdn.com/turkcdn.js" defer></script>
Then add the command to the image URL. The image itself stays the same; the script adds the behavior.
| Command | What it does |
|---|---|
_o-on | On click, the page dims and the full image opens large. Clicking the large image zooms in 2×; the arrows move to the other images on the page; ESC, × or clicking outside closes it. |
_z-on | Like on shopping sites: while the mouse is over the image, that area is shown up close, either inside the image or in a separate panel next to it. On touch screens, tapping opens the large view. |
If you don't want to add the command to every URL, choose a Viewer (Görüntüleyici) setting for the template in the dashboard; every URL that uses that template (resim_akart.jpg) becomes zoomable automatically. If you use a custom domain, add it to the script tag: data-domains="cdn.mysite.com".
You can use both together: urun/kapak_kart_o-on_z-on.webp. For the large views, the script requests two variants of the same URL, and you can use them too:
_full: the size is ignored and the whole image is returned at its original size._hd: the same size and crop at 3× resolution, never larger than the original.
Viewer settings
These are set per zone in the Viewer section under the Sizes tab in the dashboard. If you turn off the overlay or zoom, it stops immediately, without touching your URLs.
| Setting | Options |
|---|---|
overlay, zoom | On / off (on by default) |
overlay_bg, overlay_opacity | Background color #rrggbb and darkness 50-100% (default #0a0c12, 90%) |
overlay_radius | Corner radius of the large image: none, sm, md |
overlay_buttons | Arrows and close button: light, dark |
overlay_caption | Show the alt text below the image |
zoom_scale | Magnification: 2, 2.5, 3, 4 |
zoom_place | inside: inside the image; side: a panel to the right of the image (inside if there is no room) |
zoom_lens | Lens over the image when the side panel is used: none, square, round |
API: GET / PUT /zones/{zone}/viewer. The script reads the settings and the templates that have a viewer from the zone's turkcdn.json file: https://cdn.turkcdn.com/{zone}/turkcdn.json.
The script is about 4 KB and has no dependencies. If you don't add it, images with these commands behave like regular images.
Formats and limits
| Image uploads | JPG, PNG, WebP, GIF |
|---|---|
| Output formats | JPG, PNG, WebP, AVIF |
| Image size | Up to 20 MB |
| Video uploads | MP4, MOV, M4V, WebM (up to 200 MB) |
| File path | Up to 512 characters. Folder names can't be empty or start with a dot. |
The format is chosen by the extension in the URL. The .jpeg extension is read as .jpg.
Caching and cleanup
- Copies are generated on the first request and then served from the CDN. Responses include
Cache-Control: public, max-age=86400and anETag. - Images can be used from any domain (
Access-Control-Allow-Origin: *). - If you upload again to the same path, the old copies and the CDN cache are purged. The URL stays the same.
- Copies that aren't requested for 30 days are deleted automatically and regenerated if requested again. The original file is never deleted.
Video
Uploaded videos are converted to H.264 MP4 in the background. Their URLs return 404 until the conversion finishes, then become available. Range requests are supported.
| Requested URL | Result |
|---|---|
tanitim/klip.mp4 | Default conversion, long side up to 1920 px |
tanitim/klip_mobil.mp4 | Video preset named mobil ("mobile") |
tanitim/klip.jpg | Poster frame |
Video presets are separate from image presets. Width and height must be even numbers between 32 and 3840. mode defaults to contain, and quality is set with crf (18-35, default 23; a lower number means higher quality). When you add a new preset, the videos in your account are reprocessed at that size.
API
The base URL is https://api.turkcdn.com/v1. Send your API key in the Authorization header with every request:
Authorization: Bearer tcdn_...
Keep your key on the server side; don't put it in a browser or a mobile app. If you think it has leaked, delete it in the dashboard and create a new one.
Each key belongs to a zone; the images and videos you upload are published at that zone's URL.
Images
PUT/images/{path} | Upload. The body is the file itself. An existing file at the same path is overwritten. |
DELETE/images/{path} | Delete. Returns 204 on success. |
GET/images | Lists the images in the account |
Upload and list return these fields for each image:
{
"id": 128,
"path": "urun/kapak.jpg",
"size": 1258291,
"width": 2400,
"height": 2400,
"created_at": 1792540800,
"url": "https://cdn.turkcdn.com/magazam/urun/kapak.jpg"
}
Presets
GET/presets | Lists global presets. With ?image_id=128 you get the presets specific to that image. |
POST/presets | Adds a preset |
PUT/presets/{id} | Updates a preset and purges its old copies |
DELETE/presets/{id} | Deletes a preset |
The body is JSON; the fields are listed in the table in the Sizes and templates section.
curl -X POST \ -H "Authorization: Bearer tcdn_..." \ -H "Content-Type: application/json" \ -d '{"name": "kart", "width": 400, "height": 400, "mode": "cover", "anchor": "t"}' \ https://api.turkcdn.com/v1/presets
import requests
r = requests.post(
"https://api.turkcdn.com/v1/presets",
headers={"Authorization": "Bearer tcdn_..."},
json={"name": "kart", "width": 400, "height": 400, "mode": "cover", "anchor": "t"},
)
r.raise_for_status()
Watermark
GET/watermark | Watermark settings; null if none has been uploaded |
PUT/watermark | Uploads or replaces the logo. The body is the file itself; png, webp or jpg, up to 2 MB. |
PUT/watermark/settings | JSON: anchor (position, default br), opacity (10-100), scale (percentage of the image width, 5-50) |
DELETE/watermark | Removes the watermark |
Videos
PUT/videos/{path} | Upload. The body is the video file. |
DELETE/videos/{path} | Delete |
GET/videos | Lists videos and their status |
GET POST/video-presets | Lists or adds video presets |
PUT DELETE/video-presets/{id} | Updates or deletes a video preset |
The video status is in the status field: queued, processing, ready or failed. The response includes the playback URL in url and the poster frame in poster_url.
Keys
GET/keys | Lists keys (only the prefix is shown) |
POST/keys | Creates a new key with {"name": "..."}. The full key is returned only in this response. |
DELETE/keys/{id} | Revokes a key |
Zones
An account can have multiple zones; each zone has its own URL (https://cdn.turkcdn.com/{zone}/), images, videos, presets, domains and keys. Image, video, storage and traffic limits apply to the total across all zones. Number of zones: Webmaster and Başla 1, Geliştir 3, Büyüt 10. The free Webmaster plan also has daily limits: 50 MB of traffic and 1,000 requests per day. When either limit is reached, images aren't served until 03:00 the next day.
GET/zones | Lists zones. When called with a key, only that key's zone is returned. |
PUT/zones/{zone}/origin | Sets the origin URL: {"origin": "https://mysite.com"}; null turns it off. |
How the origin URL works is described in Origin pull.
Zones can be added and deleted only in the dashboard. Deleting a zone permanently deletes its images, videos, presets, domains and keys, and also purges its URLs from the CDN cache.
Stats
GET/stats returns the number of images, copies and presets, and the space they take up in bytes: images, image_bytes, variants, variant_bytes, presets.
Errors
For failed requests, the body has the form {"error": "description"}. API error messages are currently returned in Turkish.
| Code | Meaning |
|---|---|
400 | Invalid request: unsupported format, empty file, invalid preset value, video over the 200 MB limit |
401 | Missing or invalid key |
404 | File, preset or record not found |
409 | Conflict: the same preset or name already exists, or a video already exists at the same path |
413 | Image exceeds the 20 MB limit |