{"openapi":"3.1.0","info":{"title":"Shortlink API","version":"1.0.0","description":"API publik untuk membuat dan mengelola link pendek beserta analytics-nya. Semua endpoint memerlukan header Authorization: Bearer <API key> (buat di halaman API pada dashboard). Rate limit 120 request/menit per key; sisa kuota ada di header x-ratelimit-*."},"servers":[{"url":"https://localhost:3000"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"sl_..."}},"schemas":{"Link":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","format":"uri","description":"Tujuan default"},"title":{"type":"string","nullable":true},"androidUrl":{"type":"string","nullable":true,"description":"Tujuan khusus Android"},"iosUrl":{"type":"string","nullable":true,"description":"Tujuan khusus iOS"},"geoTargets":{"type":"string","nullable":true,"description":"JSON per kode negara, mis. {\"ID\":\"https://...\"}"},"abUrl":{"type":"string","nullable":true,"description":"URL varian B (A/B testing)"},"abSplit":{"type":"integer","nullable":true,"description":"Persen trafik ke varian B"},"tags":{"type":"string","nullable":true,"description":"Tag dipisah koma"},"archived":{"type":"boolean"},"expiresAt":{"type":"string","format":"date-time","nullable":true},"expiredUrl":{"type":"string","nullable":true},"hasPassword":{"type":"boolean","description":"Hash password tidak pernah dikirim"},"domainId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"clicks":{"type":"integer"}}},"LinkInput":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"slug":{"type":"string","description":"Kosongkan untuk slug acak"},"title":{"type":"string"},"androidUrl":{"type":"string","format":"uri"},"iosUrl":{"type":"string","format":"uri"},"geoTargets":{"type":"object","additionalProperties":{"type":"string"},"description":"Kunci = kode negara ISO-3166 alpha-2, mis. {\"ID\":\"https://...\"}"},"ogTitle":{"type":"string"},"ogDescription":{"type":"string"},"ogImage":{"type":"string","format":"uri"},"abUrl":{"type":"string","format":"uri"},"abSplit":{"type":"integer","minimum":1,"maximum":99},"tags":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"expiresAt":{"type":"string","format":"date-time"},"expiredUrl":{"type":"string","format":"uri"},"password":{"type":"string"},"domainId":{"type":"string"}}}}},"paths":{"/api/v1/links":{"get":{"summary":"Daftar link (berpaginasi)","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":100,"maximum":1000}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Cari di slug, URL, dan judul"}],"responses":{"200":{"description":"Daftar link","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Link"}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}},"401":{"description":"Kesalahan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Kesalahan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"post":{"summary":"Buat link baru","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkInput"}}}},"responses":{"201":{"description":"Link dibuat","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"400":{"description":"Kesalahan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Slug sudah dipakai","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/links/{idOrSlug}":{"parameters":[{"name":"idOrSlug","in":"path","required":true,"schema":{"type":"string"},"description":"ID internal atau slug link"}],"get":{"summary":"Detail satu link","responses":{"200":{"description":"Link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"404":{"description":"Kesalahan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"patch":{"summary":"Ubah link","description":"Field yang tidak dikirim dibiarkan. String kosong pada field opsional menghapus nilainya. Tambahan: archived (boolean), removePassword (boolean).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkInput"}}}},"responses":{"200":{"description":"Link setelah diubah","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"400":{"description":"Kesalahan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Kesalahan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"delete":{"summary":"Hapus link","responses":{"200":{"description":"Terhapus","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"404":{"description":"Kesalahan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/links/{idOrSlug}/stats":{"parameters":[{"name":"idOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","enum":[7,30,90],"default":30}}],"get":{"summary":"Analytics satu link","responses":{"200":{"description":"Agregat: total, klik harian, jam & hari ramai, pengunjung unik, serta breakdown referrer/browser/OS/perangkat/negara/varian.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"rangeClicks":{"type":"integer"},"prevRangeClicks":{"type":"integer"},"uniqueVisitors":{"type":"integer"},"daily":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"count":{"type":"integer"}}}},"hourly":{"type":"array","items":{"type":"integer"}},"weekday":{"type":"array","items":{"type":"integer"}}}}}}},"404":{"description":"Kesalahan","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}