Katalog
Katalog uçları, size açılan villaları ve onları tanımlayan sözlükleri (özellik, lokasyon, villa tipi) verir. Hepsi GET isteğidir,
aynı kimlikle çağrılır ve ETag taşır.
Bu sayfadaki örnekler şu ortam değişkenlerini kullanır (ayrıntı Başlarken):
export TRIMANGO_BASE_URL="https://…/api/public/v1" # size verilen taban adres, sonunda / yokexport TRIMANGO_CLIENT_ID="…"export TRIMANGO_CLIENT_SECRET="…"Node örneklerinde ortak bir yardımcı var:
const BASE = process.env.TRIMANGO_BASE_URLconst AUTH = 'Basic ' + Buffer.from(`${process.env.TRIMANGO_CLIENT_ID}:${process.env.TRIMANGO_CLIENT_SECRET}`).toString('base64')
export async function api(path, { etag } = {}) { const res = await fetch(BASE + path, { headers: { Authorization: AUTH, Accept: 'application/json', ...(etag ? { 'If-None-Match': etag } : {}) }, }) if (res.status === 304) return { notModified: true, etag } if (!res.ok) throw new Error(`${res.status} ${await res.text()}`) return { data: await res.json(), etag: res.headers.get('etag') }}Hangi villalar döner
Bölüm başlığı “Hangi villalar döner”Katalogda yalnız iki durumdaki villa görünür:
status |
Anlamı |
|---|---|
FOR_SALE |
Satışta. |
CLOSED |
Satışa geçici olarak kapalı. Listede ve detayda görünür, ama kapalı olduğu dönemde teklif ve talep alınmaz. Ayrıntı Müsaitlik. |
Taslak, yayından kaldırılmış ya da arşivlenmiş villa hiçbir uçta görünmez; detayı 404 döner. Kendi kataloğunuzda bir villanın 404 dönmesini “artık satılmıyor” olarak yorumlayın.
Villa listesi
Bölüm başlığı “Villa listesi”GET /villas süzülmüş, sıralanmış ve sayfalanmış villa kartlarını döner.
curl -s -u "$TRIMANGO_CLIENT_ID:$TRIMANGO_CLIENT_SECRET" \ "$TRIMANGO_BASE_URL/villas?location=kalkan,kas&guests=6&features=ozel-havuz&sort=price_asc&page=1&page_size=48&facets=false"const { data } = await api('/villas?location=kalkan,kas&guests=6&features=ozel-havuz&sort=price_asc&page_size=48&facets=false')console.log(data.total, data.items.map((v) => v.code))Süzgeçler
Bölüm başlığı “Süzgeçler”| Parametre | Kural |
|---|---|
location |
İl, ilçe ya da belde adresi (slug), virgülle birden çok; biri tutması yeter. Adresler GET /locations’dan. Aynı adlı ilçe birden çok ilde varsa adres il önekiyle gelir (mugla-merkez); sorguda mugla/merkez de kabul edilir. Belde takma adı da çalışır (Hisarönü → hisaronu); o zaman yanıttaki resolved_location eşlendiği asıl adresi verir. |
region |
Bölge kimlikleri (uuid, virgülle). GET /locations yanıtındaki regions[].id. |
type |
Villa tipi adresleri, virgülle; biri tutması yeter. GET /types/counts’tan. |
features |
Özellik kimlikleri ya da kalıcı adresleri (slug), virgülle; hepsi olan villalar. Bilinmeyen değer hiçbir villayla eşleşmez. GET /features’tan. |
guests |
Kapasite ile ek kişi hakkının toplamı en az bu kadar olan villalar. |
bedrooms, bathrooms |
En az yatak odası, en az banyo. |
min_price, max_price |
Başlayan gecelik fiyatın TL karşılığına göre bant. |
max_sea_distance_m |
Denize ya da plaja en çok bu kadar metre. Mesafesi girilmemiş villa çıkar. |
pet_friendly, breakfast_included |
true: evcil hayvan kabul eden villalar; kahvaltı fiyata dahil olan villalar. |
deal |
Fırsat türleri (LAST_MINUTE, EARLY_BOOKING, CAMPAIGN, GIFT_NIGHT), virgülle; en az biri bugün yayında olan villalar. |
featured |
true: yalnız öne çıkarılan villalar. |
q |
Villa adı ya da kodu. Büyük/küçük harf ve Türkçe harf farkı gözetilmez; bütün kelimeler geçmeli. |
check_in, check_out, adults, children, available_only |
Tarihli liste: her kartta uygunluk ve toplam fiyat. Müsaitlik sayfasında. |
month |
Ay modu (YYYY-MM): kartta o aydaki boş haftalar. Müsaitlik sayfasında. |
Bütün parametrelerin tam listesi ve sınırları API başvurusunda.
Sıralama
Bölüm başlığı “Sıralama”sort şu değerlerden biridir:
| Değer | Sıra |
|---|---|
recommended (varsayılan) |
Önce öne çıkarılan villalar, sonra fırsatlı villalar, sonra son güncellenen. |
price_asc, price_desc |
Başlayan fiyatın TL karşılığı; fiyatı olmayan villalar sonda. |
newest |
Son eklenen önce. |
capacity_desc, capacity_asc |
Kapasite; eşitlikte başlayan fiyat. |
rating_desc |
Misafir puanı; eşitlikte yorum sayısı, yorumsuz villalar sonda. |
Sayfalama
Bölüm başlığı “Sayfalama”page 1’den başlar; page_size 1–48, varsayılan 24. Yanıttaki total süzgece uyan bütün villaların sayısıdır, sayfa sayısını
Math.ceil(total / page_size) ile bulun.
{ "items": [ { "id": "01990c1e-7a3b-7c2d-9e4f-5a6b7c8d9e0f", "code": "ABC-1042", "slug": "villa-zeytin", "slug_en": "villa-olive", "title": "Villa Zeytin", "status": "FOR_SALE", "location": { "slug": "kalkan", "name": "Kalkan", "district": { "slug": "kas", "name": "Kaş" }, "city": { "slug": "antalya", "name": "Antalya" }, "region": null }, "capacity": 6, "bedrooms": 3, "bathrooms": 3, "cover_url": "https://…", "photos": ["https://…", "https://…"], "types": [{ "slug": "balayi-villalari", "name": "Balayı villaları" }], "from_price": { "nightly": 450, "currency": "EUR", "nightly_try": 16425 }, "deals": [], "offers": [], "lat": 36.2654, "lng": 29.4141, "sea_distance_m": 800, "stay": null, "month_free_weeks": null, "month_min_nightly_try": null, "month_weeks": null, "rating": 4.8, "review_count": 12, "has_pool": true, "pet_friendly": false, "breakfast_included": false // … is_featured, is_sort_priority, ribbon_text, ribbon_text_2, why } ], "facets": null, "nearby_free": [], "resolved_location": null, "total": 37, "page": 1, "page_size": 48, "occupied_count": null, "personalized": false}Karttaki önemli alanlar:
| Alan | Anlamı |
|---|---|
id |
Villanın kalıcı kimliği (uuid). Kendi veritabanınızda anahtar olarak bunu kullanın. |
code |
Villa kodu, Trimango genelinde tekil. Biçimini varsaymayın (ABC-1042 gibi önekli ya da eski villalarda VR-<n>). Kod nadiren değişebilir; yanıttaki değer esastır. |
slug, slug_en |
Villanın Türkçe ve İngilizce adresi. Değişebilir; anahtar olarak kullanmayın. |
location |
Belde (slug, name), ilçesi, ili ve varsa bölgesi. |
capacity |
Standart kişi sayısı. Ek kişi hakkı detayda extra_person.max_extra. |
cover_url, photos |
Kapak ve ilk 5 fotoğrafın küçük boyu. Büyük boylar detayda; bkz. Fotoğraflar. |
from_price |
Başlayan fiyat: bugünden sonra biten sezonların en düşük gecelik fiyatı, villanın para biriminde (nightly, currency) ve TL karşılığı (nightly_try, kur yoksa null). Sezonu olmayan villada null. Gerçek konaklama fiyatı için Fiyat ve teklif. |
deals, offers |
Villayı kapsayan, bugün yayındaki fırsatların türü ve ayrıntısı. |
rating, review_count |
Yayındaki misafir yorumlarının ortalaması (1–5) ve sayısı; yorum yoksa rating null. |
stay, month_* |
Yalnız tarihli listede ve ay modunda dolu; diğer durumlarda null. |
Villa detayı
Bölüm başlığı “Villa detayı”GET /villas/{slug} villanın bütün içeriğini, takvimini ve sezon fiyatlarını döner. Yoldaki değer üç biçimde olabilir:
- Türkçe adres (
slug):villa-zeytin - İngilizce adres (
slug_en):villa-olive - Villa kodu:
ABC-1042
Kod eşleşmesi kesindir; bu yüzden eşitlemede villayı koduyla açmanızı öneririz. Kodu değişen bir villa eski koduyla bir süre daha
açılır, yanıttaki code yeni koddur: kaydınızı güncelleyin.
curl -s -u "$TRIMANGO_CLIENT_ID:$TRIMANGO_CLIENT_SECRET" \ "$TRIMANGO_BASE_URL/villas/ABC-1042?calendar_months=12"const { data: villa } = await api(`/villas/${encodeURIComponent('ABC-1042')}?calendar_months=12`)calendar_months (1–24, varsayılan 18) takvimin bugünden kaç ay ileriye verileceğidir.
{ "id": "01990c1e-7a3b-7c2d-9e4f-5a6b7c8d9e0f", "code": "ABC-1042", "slug": "villa-zeytin", "slug_en": "villa-olive", "title": "Villa Zeytin", "status": "FOR_SALE", "closed_until": null, "location": { "slug": "kalkan", "name": "Kalkan", "district": { "slug": "kas", "name": "Kaş" }, "city": { "slug": "antalya", "name": "Antalya" }, "region": null }, "capacity": 6, "bedrooms": 3, "bathrooms": 3, "short_description": "Kalkan'a yürüme mesafesinde, deniz manzaralı …", "content_html": "<p>…</p>", "photos": [ { "url": "https://…", "thumb_url": "https://…", "width": 1600, "height": 1067, "blurhash": "LKO2?U%2Tw=w]~RBVZRi};RPxuwH", "category": "POOL", "alt_text": "Havuz ve teras" } ], "video_url": null, "lat": 36.2654, "lng": 29.4141, "size_m2": 180, "views": [{ "code": "SEA", "name": "Deniz" }], "privacy": "DETACHED", "rooms": [ { "type": "Yatak odası", "kind": "BEDROOM", "name": null, "floor": 1, "en_suite": true, "beds": [{ "code": "DOUBLE", "name": "Çift kişilik", "count": 1 }] } ], "features": [ { "id": "01990a00-1111-7000-8000-000000000001", "name": "Özel havuz", "slug": "ozel-havuz", "icon": "pool", "category": "havuz", "category_name": "Havuz", "kind": "FEATURE", "note": null } ], "pools": [ { "type": "Açık havuz", "width_cm": 400, "length_cm": 800, "depth_cm": 150, "heatable": true, "fenced": false, "sun_hours": 8, "fee": 1500, "fee_unit": "DAY", "note": null } ], "house_rules": [ { "code": "PETS", "name": "Evcil hayvan", "icon": null, "allowed": false, "note": null } ], "check_in_time": "16:00", "check_out_time": "10:00", "stay_rules": [{ "from": null, "to": null, "min_nights": 5, "max_nights": null, "check_in_days": [] }], "distances": [{ "label": "Plaj", "distance_m": 800, "type": "BEACH", "note": null }], "sea_distance_m": 800, "calendar": { "from": "2026-10-27", "to": "2027-10-27", "busy": [{ "start": "2027-06-12", "end": "2027-06-19" }] }, "currency": "EUR", "extra_person": { "max_extra": 2, "adult_per_night": 40, "child_per_night": 20 }, "canonical": null, "document_number": "12345" // … trail, types, from_price, seasons, fees, offers, deposit_rate, deposit_only, damage_deposit, // instant_booking, cancellation_note, heating, internet_mbps, parking_spaces, year_built …}Detayı başlıklara göre okuyun:
| Konu | Alanlar |
|---|---|
| Metin | title, short_description (düz metin), content_html (HTML). |
| Fotoğraf ve video | photos[], cover_url, video_url. Bkz. Fotoğraflar. |
| Kapasite ve odalar | capacity, bedrooms, bathrooms, extra_person (en çok ek kişi ve gecelik ek kişi ücreti), rooms[] (oda türü kind: BEDROOM, BATHROOM, LIVING, KITCHEN, OTHER; yataklar beds[]). |
| Özellikler | features[]. kind: FEATURE özellik, HIGHLIGHT öne çıkan özellik, INCLUDED fiyata dahil, EXCLUDED fiyata dahil değil. slug kalıcıdır, ad değişse de değişmez. |
| Havuz ve ısıtma | pools[] (ölçü, ısıtılabilir mi, ısıtma ücreti fee ve birimi fee_unit: DAY ya da STAY), heating[]. |
| Ev kuralları | house_rules[]. code sabit koddur (PETS, SMOKING, PARTY, EVENTS, CHILDREN, QUIET_HOURS, VISITORS); kodu olmayan kural null döner, adıyla gösterin. allowed izinli mi. |
| Konaklama kuralları | stay_rules[]: dönem (from–to, son gece dahil; ikisi de null ise her zaman), min_nights, max_nights, giriş günleri check_in_days (ISO: 1 pazartesi … 7 pazar; boşsa her gün). check_in_time, check_out_time. |
| Konum | lat, lng, location, trail (il › ilçe › belde), distances[] (yer türü type: BEACH, CENTER, MARKET, AIRPORT …), sea_distance_m. |
| Yapı | size_m2, land_m2, floor_count, single_level, wheelchair_accessible, year_built, year_renovated, views[], privacy (DETACHED müstakil, IN_COMPLEX site içinde, SHARED_GARDEN ortak bahçe), internet_mbps, parking_spaces, car_to_door, steps_to_entrance. |
| Takvim | calendar: bkz. Müsaitlik. |
| Fiyat | currency, seasons[], fees[], extra_person, offers[], deposit_rate, damage_deposit. Konaklama fiyatını kendiniz hesaplamayın: Fiyat ve teklif. |
| Belge | document_number: Kültür ve Turizm Bakanlığı Turizm İşletmesi Belgesi numarası; girilmemişse null. |
Değer verilmemiş alanlar null ya da boş dizi döner; alanlar yanıttan düşmez.
Özet listesi ve toplu eşitleme
Bölüm başlığı “Özet listesi ve toplu eşitleme”Kataloğu kendi veritabanınızda tutuyorsanız başlangıç noktası GET /villas/summaries’dir. Sayfasızdır: size açık bütün villaları
tek yanıtta, koda göre sıralı ve hafif bir özetle döner.
curl -s -u "$TRIMANGO_CLIENT_ID:$TRIMANGO_CLIENT_SECRET" \ "$TRIMANGO_BASE_URL/villas/summaries"[ { "id": "01990c1e-7a3b-7c2d-9e4f-5a6b7c8d9e0f", "code": "ABC-1042", "slug": "villa-zeytin", "slug_en": "villa-olive", "title": "Villa Zeytin", "location": { "slug": "kalkan", "name": "Kalkan", "district": { "slug": "kas", "name": "Kaş" }, "city": { "slug": "antalya", "name": "Antalya" }, "region": null }, "capacity": 6, "bedrooms": 3, "bathrooms": 3, "types": [{ "slug": "balayi-villalari", "name": "Balayı villaları" }], "cover_url": "https://…", "from_price": { "nightly": 450, "currency": "EUR", "nightly_try": 16425 }, "updated_at": "2026-10-21T08:14:03Z", "rating": 4.8, "review_count": 12, "canonical_url": null } // …]Belirli villaları istemek için ids verin (kimlik ya da kod, virgülle, en çok 100):
/villas/summaries?ids=ABC-1042,ABC-1043.
Önerilen eşitleme düzeni
Bölüm başlığı “Önerilen eşitleme düzeni”- Tam eşitleme (ilk kurulumda ve günde bir kez):
GET /villas/summariesile güncel villa listesini alın.- Listede olup sizde olmayan villaları ekleyin; sizde olup listede olmayanları satıştan kaldırın.
- Her villa için
GET /villas/{code}ile detayı okuyun. Önceki yanıtınETag’iniIf-None-Matchile gönderin; değişmemişse 304 döner ve gövde gelmez. - Sözlükleri (
/features,/locations,/types/counts) yenileyin.
- Gün içinde: webhook olayı gelince yalnız etkilenen villaları yeniden okuyun.
import { api } from './trimango.js'
export async function fullSync(db) { const { data: summaries } = await api('/villas/summaries') const liveIds = new Set(summaries.map((s) => s.id))
for (const old of await db.villaIds()) { if (!liveIds.has(old)) await db.unpublish(old) // artık size açık değil }
// Aynı anda birkaç istek yeter; dakikada 1.200 istek sınırı istemcinin bütün çağrılarını kapsar. const queue = [...summaries] const workers = Array.from({ length: 4 }, async () => { for (let s = queue.shift(); s; s = queue.shift()) { const saved = await db.villa(s.id) try { const r = await api(`/villas/${encodeURIComponent(s.code)}`, { etag: saved?.etag }) if (!r.notModified) await db.saveVilla(s.id, r.data, r.etag) } catch (e) { if (String(e.message).startsWith('404')) await db.unpublish(s.id) else throw e } } }) await Promise.all(workers)}Sözlükler
Bölüm başlığı “Sözlükler”Süzgeçlerde kullandığınız adresler ve kimlikler bu üç uçtan gelir. Seyrek değişirler; değiştiklerinde reference webhook olayı
gelir.
Özellikler
Bölüm başlığı “Özellikler”GET /features: özellikler, kategori sırasıyla.
[ { "id": "01990a00-1111-7000-8000-000000000001", "slug": "ozel-havuz", "name": "Özel havuz", "icon": "pool", "category": "havuz", "category_name": "Havuz", "filterable": true } // …]slug kalıcıdır ve GET /villas?features= kimlik yerine kabul eder. filterable: true olan özellikler süzgeç için seçilmiş olanlardır.
Kendi sisteminizdeki özellik listesine eşlerken slug’ı kullanın.
Lokasyonlar
Bölüm başlığı “Lokasyonlar”GET /locations: il › ilçe › belde ağacı ve bölgeler, villa sayılarıyla. Yalnız villası olan lokasyonlar döner.
{ "cities": [ { "slug": "antalya", "name": "Antalya", "villa_count": 42, "districts": [ { "slug": "kas", "name": "Kaş", "villa_count": 30, "locations": [ { "slug": "kalkan", "name": "Kalkan", "villa_count": 21, "is_popular": true, "lat": 36.2654, "lng": 29.4141, "region": null } // … ] } ] } ], "regions": [ { "id": "01990b00-2222-7000-8000-000000000001", "name": "Likya", "image_url": null, "villa_count": 30, "locations": ["kalkan", "kas-merkez"] } ]}- Üç düzeyin her birinin
slug’ıGET /villas?location=süzgecinde çalışır. - Aynı adlı ilçe birden çok ilde varsa ilçe adresi il önekiyle gelir (
mugla-merkez,aydin-merkez); çakışmayan ilçeler öneksizdir. Bu adresleri yanıttan aldığınız gibi saklayın. - Bölgeler (
regions) birkaç beldeyi bir araya toplar; süzgeçteregion=<id>.
Villa tipleri
Bölüm başlığı “Villa tipleri”GET /types/counts: villa tipleri, villa sayılarıyla.
[ { "slug": "balayi-villalari", "name": "Balayı villaları", "icon": null, "short_description": null, "group": null, "villa_count": 9, "show_in_menu": true, "is_family": false, "is_special_day": true } // …]slug’ı GET /villas?type= süzgecinde kullanın. Villa kartındaki ve detaydaki types[] aynı adresleri taşır.
İçerik ve fotoğraflar
Bölüm başlığı “İçerik ve fotoğraflar”Metinler
Bölüm başlığı “Metinler”content_htmlHTML’dir. Kendi arayüzünüzde gösterecekseniz izin verilen etiketleri süzerek (sanitize) çizin.short_descriptiondüz metindir.- Katalog metinleri bugün Türkçe döner.
Fotoğraflar
Bölüm başlığı “Fotoğraflar”photos[]gösterim sırasıyla gelir; ilk fotoğraf kapaktır (cover_url). Bir villada yüzü aşkın fotoğraf olabilir.urlbüyük boy (en çok 1600×1600, oran korunur),thumb_urlküçük boy (480×320, kırpılmış). Kartlardakicover_urlvephotosküçük boydur.widthveheighten-boy oranı için,blurhashyüklenirken gösterilecek bulanık önizleme için,category(EXTERIOR,POOL,BEDROOM…) vealt_texterişilebilirlik ve gruplama içindir.- Adresler mutlak ve imzalıdır. Adresin herhangi bir parçasını (boyut, yol) değiştirmeyin; imza bozulur ve görsel açılmaz.
- Dönen biçim isteğin
Acceptbaşlığına göre seçilir (WebP, AVIF ya da JPEG). Fotoğrafı sunucunuza indiriyorsanız biçimiContent-Type’tan okuyun. - Fotoğraflar değişince
villaolayıphotoskapsamıyla gelir; o villanın detayını yeniden okuyun.
Canonical
Bölüm başlığı “Canonical”Detaydaki canonical ve özetteki canonical_url, villanın asıl sayfasının başka bir sitede olduğunu gösterir:
null: başka bir asıl sayfa bildirilmemiş.- Dolu:
canonical.urlvillanın Türkçe asıl sayfası,canonical.url_enİngilizcesi,canonical.tenant_nameo sayfanın sahibi firmanın marka adı. Özettekicanonical_url,canonical.urlile aynıdır.
Değişiklikleri webhook ile yakalama
Bölüm başlığı “Değişiklikleri webhook ile yakalama”Trimango, kataloğunuzu etkileyen bir değişiklik olduğunda tanımladığınız adrese kısa ve imzalı bir olay gönderir. Olay veriyi taşımaz, yalnız neyin değiştiğini söyler; güncel veriyi yine API’den okursunuz. Kurulum ve imza doğrulaması Webhook sayfasında.
type |
scopes |
Kataloğunuzda ne yapılır |
|---|---|---|
villa |
detail |
villas[] içindeki villaların detayını yeniden okuyun. |
villa |
photos |
Aynı; fotoğrafları güncelleyin. |
villa |
status |
Detayı yeniden okuyun. 404 dönerse villayı satıştan kaldırın; CLOSED dönerse kapalı olarak işaretleyin. |
availability |
calendar |
Takvimi yenileyin: Müsaitlik. |
price |
prices |
Villaların sezon fiyatlarını ve başlayan fiyatını yenileyin. |
price |
deals + all_villas |
Fırsatlar değişti; villas boştur, bütün villaların fırsat ve fiyat bilgisini yenileyin. |
reference |
locations, dictionaries |
Sözlükleri (/locations, /features, /types/counts) yeniden okuyun. Villalarda sakladığınız adlar da değişmiş olabilir. |
reference |
currency |
Döviz kuru değişti; sakladığınız *_try tutarları eskidi. |
test |
— | Hiçbir şey yapmayın, 2xx dönün. |
Villa adresi değiştiyse olaydaki villada previous_slug (ve İngilizce için previous_slug_en) gelir. Villaları id ile sakladığınız
sürece yapmanız gereken yalnız yeni slug’ı kaydetmektir.
export async function onTrimangoEvent(event, db) { if (event.type === 'test') return if (event.type === 'reference') return refreshDictionaries(db) if (event.scopes.includes('all_villas')) return fullSync(db) for (const v of event.villas) { const saved = await db.villa(v.id) const key = saved?.code ?? v.slug try { const r = await api(`/villas/${encodeURIComponent(key)}`) await db.saveVilla(v.id, r.data, r.etag) } catch (e) { if (String(e.message).startsWith('404')) await db.unpublish(v.id) else throw e } }}Webhook bir şekilde kaçarsa (sunucunuz kapalıydı, olay beş denemede de ulaşmadı) günlük tam eşitleme farkı kapatır.
