Referensi API

REST API
Bangun di atas tautan Anda.

Autentikasi dengan token API, tampilkan daftar dan buat tautan, baca kunjungan, dan berlangganan webhook.

URL dasar https://letl.ink/api/v1 Hanya HTTPS

Paket Growth Ultimate
Di halaman ini

Memulai

REST API tersedia di Growth dan Ultimate. Permintaan dikirim ke https://letl.ink/api/v1 melalui HTTPS. Ruang kerja di Free atau Solo menerima 403 plan_required dari /api/v1; endpoint MCP dibatasi terpisah di Ultimate.

  1. Buka Integrasi → REST API (hanya pemilik dan admin ruang kerja).
  2. Buat token. Token ini tidak kedaluwarsa.
  3. Simpan seperti kata sandi. Satu token melayani REST API, server MCP, dan setiap platform otomatisasi yang terhubung ke ruang kerja ini, sehingga membuat ulang token akan membatalkan semuanya sekaligus.

Anggota dapat menyalin token yang sudah ada jika token telah dibuat; hanya pemilik dan admin yang dapat menggantinya.

Autentikasi

Kirim token sebagai X-API-KEY atau sebagai Authorization: Bearer. Keduanya diterima di /api/v1 dan /mcp. Permintaan tanpa token sama sekali mengembalikan 401 unauthenticated.

GET Siapa saya?
curl -H "X-API-KEY: YOUR_TOKEN" \
  https://letl.ink/api/v1/auth/me

Header setara: Authorization: Bearer YOUR_TOKEN

Konvensi

Ketentuan ini berlaku di setiap endpoint di bawah.

Amplop respons

Setiap respons yang berhasil adalah objek JSON dengan kunci data, dan kunci meta jika ada informasi tentang hasilnya — paginasi, rentang tanggal yang digunakan, apakah geografi disertakan. Setiap kegagalan adalah objek dengan kunci error yang berisi code yang stabil, message yang mudah dibaca, dan terkadang details. Buat percabangan berdasarkan code, jangan berdasarkan teks pesan.

Bentuk
// success
{ "data": { … }, "meta": { … } }

// failure
{ "error": { "code": "invalid_parameter",
             "message": "sort must be one of: created_at, clicks.",
             "details": { "parameter": "sort" } } }

Paginasi

Endpoint daftar menerima limit (1–200, default 50) dan offset. Blok meta melaporkan total, has_more, dan next_offset, sehingga Anda dapat berpindah halaman tanpa menghitung: terus panggil dengan offset = meta.next_offset hingga has_more bernilai false.

Menelusuri setiap tautan per halaman
offset=0
while [ "$offset" != "null" ]; do
  page=$(curl -s -H "X-API-KEY: $TOKEN" \
    "https://letl.ink/api/v1/links?limit=200&offset=$offset")
  echo "$page" | jq -c '.data[]'
  offset=$(echo "$page" | jq -r '.meta.next_offset')
done

Pengurutan, filter, dan pencarian

GET /links menerima sort (created_at, clicks, short_code, title, updated_at), direction (asc/desc), search (mencocokkan kode pendek, judul, dan tujuan), type, archived, favorite, dan domain. Nilai yang tidak dikenal ditolak dengan invalid_parameter beserta daftar nilai yang diizinkan, alih-alih diabaikan diam-diam.

Rentang tanggal

start_date dan end_date menggunakan YYYY-MM-DD dan mencakup kedua hari tersebut. Rentang waktu dibatasi sesuai batas retensi paket Anda — meminta riwayat setahun pada paket dengan retensi 30 hari akan mengembalikan 30 hari yang tersedia, dan meta.date_range memberi tahu rentang yang sebenarnya digunakan.

Batas laju

600 permintaan per menit per akun, dengan jendela geser. Setiap respons menyertakan X-RateLimit-Limit, X-RateLimit-Remaining, dan X-RateLimit-Reset (stempel waktu Unix). Melebihi batas akan mengembalikan 429 rate_limited dengan header Retry-After dalam detik. Tunggu sesuai Retry-After, jangan langsung mencoba ulang.

Header pada setiap respons
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 586
X-RateLimit-Reset: 1789000816

Pembuatan versi

Jalur membawa versi. Menambahkan kolom pada respons atau parameter opsional baru bukan perubahan yang merusak dan dapat terjadi kapan saja, jadi uraikan secara defensif dan abaikan kunci yang tidak Anda kenali. Apa pun yang akan mengubah atau menghapus kolom yang sudah ada dirilis dengan awalan versi baru.

Endpoint

Akun

GET /me Uji koneksi

Identitas, ruang kerja, paket, dan setiap hak yang dimiliki paket tersebut. Cara termudah untuk memverifikasi token dan mengetahui apa yang boleh dilakukan akun sebelum Anda mencobanya.

GET cURL
curl -H "X-API-KEY: YOUR_TOKEN" \
  https://letl.ink/api/v1/me
Respons 200
{
  "data": {
    "user": { "id": 1, "email": "[email protected]", "name": "You" },
    "workspace": { "id": 12, "name": "My Workspace", "block_bots": true },
    "plan": {
      "id": "growth",
      "name": "Growth",
      "limits": {
        "links": 200,
        "monthly_clicks": 100000,
        "custom_domains": 3,
        "qr_codes": 30,
        "retention_days": 365
      },
      "features": {
        "api": true,
        "webhooks": true,
        "integrations": true,
        "ai_access": false,
        "geo_analytics": false,
        "smart_link_types": true
      }
    },
    "base_domain": "letl.ink"
  }
}
GET /usage

Seberapa banyak setiap kuota terpakai di bulan tagihan ini. Gunakan untuk memperingatkan pelanggan sebelum mencapai batas klik terlacak — setelah melewatinya, pengalihan tetap berfungsi, tetapi klik berhenti dicatat.

Respons 200
{
  "data": {
    "links": { "used": 42, "limit": 200, "remaining": 158, "percent_used": 21.0 },
    "clicks_this_month": { "used": 8140, "limit": 100000, "remaining": 91860, "percent_used": 8.1 },
    "custom_domains": { "used": 1, "limit": 3, "remaining": 2, "percent_used": 33.3 },
    "qr_codes": { "used": 4, "limit": 30, "remaining": 26, "percent_used": 13.3 }
  },
  "meta": { "plan": "growth", "period": "2026-09" }
}
GET /domains

Domain kustom di ruang kerja dan apakah masing-masing sudah menyelesaikan verifikasi DNS. Hanya domain terverifikasi yang dapat digunakan sebagai kolom domain saat membuat tautan.

GET /integrations

Setiap integrasi yang ditawarkan produk, apakah paket Anda menyertakannya, apakah ruang kerja ini sudah menghubungkannya, dan bagaimana pengirimannya berjalan — status terakhir, error terakhir, dan jumlah kegagalan berturut-turut. Berguna untuk memantau banyak ruang kerja.

Tautan

Analitik

GET /analytics/summary

Angka utama untuk seluruh ruang kerja: klik sepanjang waktu dan dalam rentang, pengunjung unik, pindaian QR, hari puncak, serta distribusi jam dan hari. Menerima days (default 30, dibatasi sesuai retensi Anda).

Respons 200 (diringkas)
{
  "data": {
    "window_days": 30,
    "clicks": {
      "total": 24592, "window": 8140, "last_7_days": 2103,
      "daily_average": 271,
      "peak_day": { "date": "Sep 02", "clicks": 612 }
    },
    "visitors": { "unique_total": 18204, "unique_window": 6021 },
    "qr": { "scans_total": 940, "scans_window": 310 },
    "timing": {
      "by_hour": [12, 4, 2, …],
      "by_weekday": [1420, 1610, 1585, 1490, 1310, 480, 245],
      "peak_hour": { "peakHour": 14, "peakValue": 812, "label": "14:00–14:59" },
      "peak_weekday": { "peakDay": 1, "peakValue": 1610, "label": "Tuesday" }
    },
    "links": { "active": 42, "limit": 200 }
  },
  "meta": { "plan": "growth", "geo_included": true, "retention_days": 365 }
}
GET /analytics/timeseries

Jumlah klik harian, siap dijadikan grafik. Berikan link_id untuk membatasinya ke satu tautan, dan days untuk mengatur rentang. Hari tanpa trafik dikembalikan sebagai nol, bukan dihilangkan, sehingga deretnya selalu bersambung.

Respons 200
{
  "data": [
    { "date": "Sep 04", "clicks": 22 },
    { "date": "Sep 05", "clicks": 11 }
  ],
  "meta": { "window_days": 7, "total": 33, "link_id": null }
}
GET /analytics/breakdown

Klik yang dikelompokkan berdasarkan satu dimensi, dengan porsi setiap baris dari total.

Parameter kueri

  • dimension string

    channel, referrer, device, browser, os, brand, variation atau country. browser, os, brand, dan variation memerlukan link_id.

    Wajib
  • link_id integer

    Batasi ke satu tautan. Hilangkan untuk seluruh ruang kerja.

    Opsional
  • limit integer

    1–100. Default: 10.

    Opsional
Respons 200
{
  "data": [
    { "label": "Search", "value": 215, "share": 33.1 },
    { "label": "Social", "value": 201, "share": 30.9 },
    { "label": "Direct / none", "value": 142, "share": 21.8 }
  ],
  "meta": { "dimension": "channel", "link_id": 49, "total": 650 }
}
GET /events Berhalaman

Aliran kunjungan mentah di semua tautan di ruang kerja, dari yang terbaru. Ini pengganti modern untuk GET /visits: data yang sama, amplop standar, dukungan limit dan offset.

Respons 200
{
  "data": [
    {
      "id": 2691,
      "link_id": 49,
      "short_code": "spring",
      "occurred_at": "2026-09-10T22:45:33+00:00",
      "ip_address": "203.0.113.7",
      "referrer": "https://twitter.com/",
      "browser": "Chrome",
      "os": "iOS",
      "device_type": "mobile",
      "device_brand": "Apple",
      "country": "US",
      "variation": "control"
    }
  ],
  "meta": { "limit": 50, "returned": 50, "geo_included": true }
}

Webhook

GET /hooks

Endpoint webhook yang terdaftar di akun ini.

POST /hooks

Daftarkan endpoint HTTPS untuk menerima payload JSON pada setiap klik yang tercatat. Hingga 25 per akun. Pengiriman yang gagal dicoba ulang secara otomatis.

Body JSON

  • target_url

    Harus https://.

    Wajib
  • event

    Default: link_visited, yang saat ini merupakan satu-satunya event.

    Opsional
POST cURL
curl -X POST https://letl.ink/api/v1/hooks \
  -H "X-API-KEY: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"target_url": "https://example.com/hooks/clicks"}'
DELETE /hooks/{id}

Hapus endpoint webhook. POST /hooks/subscribe dan DELETE /hooks/unsubscribe/{id} tetap tersedia untuk alur REST Hook Zapier.

Lama

GET /auth/me Lama

Uji koneksi versi awal: mengembalikan id pengguna, email, serta id/nama ruang kerja Anda sebagai objek datar. GET /me mengembalikan identitas yang sama beserta batas paket dan flag fitur Anda, dan merupakan pilihan yang lebih baik untuk kode baru.

GET cURL
curl -H "X-API-KEY: YOUR_TOKEN" \
  https://letl.ink/api/v1/auth/me
Respons 200
{
  "id": 1,
  "email": "[email protected]",
  "workspace_id": 12,
  "workspace_name": "My Workspace"
}
GET /visits Lama

50 kunjungan terbaru di seluruh ruang kerja sebagai array JSON polos — tanpa amplop — menggunakan nama kolom visit_id, visit_time, link_shortcode, dan visitor_*. Inilah yang dibaca langkah "perform list" REST Hook Zapier, sehingga bentuknya dibekukan. Gunakan GET /events untuk pengembangan baru.

POST /hooks/subscribe Zapier

Subscribe REST Hook. Menerima target_url dan event opsional (default link_visited) dan mengembalikan langganan yang dibuat secara datar, tanpa amplop. POST /hooks adalah operasi yang sama dalam bentuk standar.

DELETE /hooks/unsubscribe/{id} Zapier

Unsubscribe REST Hook, mengembalikan {"success": true}. DELETE /hooks/{id} adalah padanannya dalam bentuk standar.

Error

  • 400 invalid_request

    Body bukan objek JSON, atau kolom wajib tidak ada.

  • 400 invalid_parameter

    Parameter kueri salah format atau di luar nilai yang diizinkan. details.parameter menyebutkan parameter yang bermasalah.

  • 401 unauthenticated

    Tidak ada token yang dikirim. Tambahkan X-API-KEY atau Authorization: Bearer.

  • 401 invalid_token

    Token tidak cocok dengan akun mana pun. Token mungkin telah dibuat ulang.

  • 403 plan_required

    Paket akun tidak menyertakan endpoint atau fitur ini. details.upgrade_url mengarah ke halaman tagihan.

  • 403 forbidden

    Sudah terautentikasi, tetapi tidak diizinkan — misalnya anggota yang mencoba melakukan aksi khusus pemilik.

  • 404 not_found

    Sumber daya tidak ada di ruang kerja ini. Id dari ruang kerja lain dilaporkan sebagai tidak ditemukan, bukan dilarang.

  • 409 conflict

    Permintaan bertentangan dengan kondisi saat ini — batas webhook sudah tercapai, atau akun belum memiliki ruang kerja.

  • 422

    Dikembalikan oleh POST /links/bulk jika setiap baris dalam batch gagal. Periksa meta.errors.

  • 429 rate_limited

    Lebih dari 600 permintaan dalam satu menit terakhir. Tunggu selama Retry-After detik.

Endpoint lama GET /visits dan GET /links/{id}/visits mengembalikan array JSON polos dengan nama kolomnya sendiri dan dibekukan untuk integrasi Zapier yang sudah dibangun di atasnya. Kode baru sebaiknya menggunakan GET /events dan GET /links/{id}/events, yang menggunakan amplop standar dan mendukung paginasi.

Masih ada pertanyaan?

Kami siap membantu. Hubungi kami dan kami akan membalas secepat mungkin.