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.

  1. 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.
  2. In the Sizes (Ölçüler) section, define the sizes your site uses, for example 400×400 named kart. The name is up to you; kart is Turkish for "card".
  3. 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

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 URLResult
urun/kapak.jpgThe original file
urun/kapak.webpWebP at the original size
urun/kapak_kart.avifkart template, AVIF
urun/kapak_kart_s.webpkart size, fitted without cropping. Command order doesn't matter: _s_kart works too.
urun/kapak_400x400.jpgGenerated if 400×400 is in your allowed sizes
urun/kapak_w400.webpWidth 400, height from the aspect ratio; _h400 does the reverse. This size must also be in your allowed sizes.
urun/kapak_akart.webpakart template with all its settings: size, crop, effects, viewer
urun/kapak_akart_300x250.webpakart template at 300×250. Returns 404 if 300×250 is not in your allowed sizes.
urun/kapak_th_kart.webpLegacy 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.

Only sizes and templates defined in your account are generated. If you request an undefined size or a file that doesn't exist, you get a 404. This way nobody can create processing load by typing random sizes into your URLs.

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

  1. In the dashboard, on the Zones (Alanlar) page, click Origin: Add (Kaynak: Ekle) next to your zone.
  2. 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.
  3. In the image URLs on your pages, replace https://mysite.com with https://cdn.turkcdn.com/{zone} and add the size you want to the file name.
HTML
<!-- 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 URLFetched from origin
urun/ayakkabi.jpgmysite.com/urun/ayakkabi.jpg
urun/ayakkabi_300x250.jpgmysite.com/urun/ayakkabi.jpg
urun/ayakkabi_kart.webpayakkabi.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.
Origin pull and uploads work together: an image that exists in the zone is always served from the zone, and the origin is contacted only for images that aren't there.

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.

FieldValue
nameRequired for templates. 1-32 characters; lowercase letters, digits and hyphens. Can't look like a size, such as 120x60 or w400.
width, height0 to 4000 pixels; if one is 0 it is calculated from the aspect ratio, but both can't be 0
modecover (default): fills the area and crops the overflow. contain: fits while keeping the aspect ratio, never upscales.
anchorCrop anchor: tl, t, tr, l, c (default), r, bl, b, br
quality1 to 100, default 82
image_idIf set, the preset applies only to that image
effectsTemplates only. Styling commands, written as in the URL: rounded-lg_border-2-eeeeee
viewerTemplates 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.

CommandTurkish aliasWhat it does
_rounded-sm, _rounded, _rounded-md, _rounded-lg, _rounded-xl_yuvarlak-az, _yuvarlak, _yuvarlak-orta, _yuvarlak-buyuk, _yuvarlak-cokRounds the corners, from smallest to largest
_rounded-full_yuvarlak-tamCorner radius of half the short side: a pill on a rectangle, a circle on a square. Doesn't crop.
_circle_daireCrops a square from the center and makes it a circle
_border, _border-thick_cerceve, _cerceve-kalinThin 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-f5f5f5Fills 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-cokThe 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_griBlack and white
_blur-low, _blur, _blur-high_bulanik-az, _bulanik, _bulanik-cokLight, medium or strong blur
_shadow-low, _shadow, _shadow-high_golge-az, _golge, _golge-cokLight, normal or strong shadow; the size grows because space is added around the edges
_opacity-50_opaklik-50How 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_filigranApplies 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:

HTML
<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.

CommandWhat it does
_o-onOn 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-onLike 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.

SettingOptions
overlay, zoomOn / off (on by default)
overlay_bg, overlay_opacityBackground color #rrggbb and darkness 50-100% (default #0a0c12, 90%)
overlay_radiusCorner radius of the large image: none, sm, md
overlay_buttonsArrows and close button: light, dark
overlay_captionShow the alt text below the image
zoom_scaleMagnification: 2, 2.5, 3, 4
zoom_placeinside: inside the image; side: a panel to the right of the image (inside if there is no room)
zoom_lensLens 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 uploadsJPG, PNG, WebP, GIF
Output formatsJPG, PNG, WebP, AVIF
Image sizeUp to 20 MB
Video uploadsMP4, MOV, M4V, WebM (up to 200 MB)
File pathUp 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=86400 and an ETag.
  • 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 URLResult
tanitim/klip.mp4Default conversion, long side up to 1920 px
tanitim/klip_mobil.mp4Video preset named mobil ("mobile")
tanitim/klip.jpgPoster 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:

HTTP
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/imagesLists the images in the account

Upload and list return these fields for each image:

Response
{
  "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/presetsLists global presets. With ?image_id=128 you get the presets specific to that image.
POST/presetsAdds 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

Watermark

GET/watermarkWatermark settings; null if none has been uploaded
PUT/watermarkUploads or replaces the logo. The body is the file itself; png, webp or jpg, up to 2 MB.
PUT/watermark/settingsJSON: anchor (position, default br), opacity (10-100), scale (percentage of the image width, 5-50)
DELETE/watermarkRemoves the watermark

Videos

PUT/videos/{path}Upload. The body is the video file.
DELETE/videos/{path}Delete
GET/videosLists videos and their status
GET POST/video-presetsLists 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/keysLists keys (only the prefix is shown)
POST/keysCreates 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/zonesLists zones. When called with a key, only that key's zone is returned.
PUT/zones/{zone}/originSets 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.

CodeMeaning
400Invalid request: unsupported format, empty file, invalid preset value, video over the 200 MB limit
401Missing or invalid key
404File, preset or record not found
409Conflict: the same preset or name already exists, or a video already exists at the same path
413Image exceeds the 20 MB limit