Kalkan logoKalkan
Kullanım kılavuzu

API

Kalkan Local API, kendi betiklerinizle profilleri, proxy'leri ve klasörleri yönetmenizi, tarayıcıları açıp kapatmanızı ve onları Playwright, Puppeteer ya da Selenium ile kullanmanızı sağlar. Kendi bilgisayarınızda çalışan Kalkan masaüstü uygulamasının sunduğu bir REST API'dir:

http://127.0.0.1:50360/api/v1

Tüm istekler ve yanıtlar JSON'dur. API; Starter, Pro ve Unlimited planlarında vardır (denemede yoktur).

Açma ve anahtarı alma

  1. Kalkan → Ayarlar → API bölümünü açın ve API'yi etkinleştirin.
  2. 50360 numaralı port bilgisayarınızda doluysa portu değiştirin.
  3. API anahtarını kopyalayın (kk_ ile başlar). Yeni anahtar üret yeni bir anahtar oluşturur; eskisi o anda geçersiz olur.

API, Kalkan uygulaması açık olduğu sürece çalışır. Pencere olmadan çalışması gereken sunucu ve betikler için aynı API'yi sunan geliştirici komutu adb api de vardır.

Kimlik doğrulama ve güvenlik

  • Anahtarı her istekte X-Token: <anahtar> başlığıyla gönderin. Authorization: Bearer <anahtar> da kabul edilir.
  • Anahtar yoksa ya da yanlışsa 401 unauthorized döner. Bir dakika içinde 10 yanlış anahtardan sonra API 60 saniye boyunca 429 locked yanıtı verir.
  • API yalnızca 127.0.0.1 üzerinde dinler ve yalnızca 127.0.0.1 ya da localhost adresine gelen isteklere yanıt verir (aksi halde 403 forbidden_host). Başka bilgisayarlardan erişilemez.
  • Web sayfaları için değil, betikler içindir: Origin başlığı taşıyan istekler (tarayıcıların gönderdiği) 403 forbidden_origin ile reddedilir; CORS yoktur.
  • Tek gizli bilgi anahtardır. Kod depolarına koymayın; sızarsa yenisini üretin.
  • Planınızda API yoksa her çağrı 403 plan döner. GET /status her zaman çalışır ve planınızın API'yi içerip içermediğini api_allowed alanında bildirir.

Yanıtlar ve hatalar

Başarılı bir çağrı {"ok": true, "data": …}, başarısız bir çağrı {"ok": false, "error": {"code": "…", "message": "…"}} döner.

{"ok": true, "data": {"id": "…", "running": true, "ws": "ws://127.0.0.1:49731/devtools/browser/…", "debug_port": 49731, "pid": 12345}}

{"ok": false, "error": {"code": "unauthorized", "message": "missing or wrong API key (send it as the X-Token header)"}}
DurumKodlarAnlamı
200 / 201 / 202Tamam / oluşturuldu / arka planda başlatıldı (wait: false)
400bad_requestEksik ya da geçersiz alan
401unauthorizedAPI anahtarı yok ya da yanlış
403plan, forbidden_host, forbidden_originPlanda API yok, Host yanlış ya da istek bir web sayfasından geliyor
404 / 405not_found, method_not_allowedBöyle bir profil / proxy / uç nokta yok ya da HTTP yöntemi yanlış
409running, direct, ledger, cross_osProfil açık ya da açılış bir karar gerektiriyor. direct: profilin proxy'si yok (allow_direct: true ile tekrarlayın). ledger: proxy'nin çıkış IP'si yakın zamanda başka profillerce kullanılmış; cross_os: profilin işletim sistemi bu bilgisayarda bu motora uymuyor (force: true ile tekrarlayın). Mesaj durumu açıklar.
429lockedÇok fazla yanlış anahtar, 60 saniye bekleyin
500internal, launch_failedBeklenmeyen hata ya da tarayıcı başlatılamadı
504timeoutTarayıcı timeout süresi içinde açılmadı

Motorlar

Kalkan'da dört motor vardır: Kalkan Native (önerilen; parmak izini C++ kodunda üreten, 150+ yamalı özel Chromium; uygulama arka planda kurar ve günceller), Kalkan (Chrome patch: gerçek Google Chrome'unuz, yamalı sürücüyle), Kalkan Edge (aynı katman kurulu Microsoft Edge'inizde; oluştururken "engine": "edge") ve Firefox (Windows, macOS ve Linux profilleri). Kalkan, Kalkan Edge ve Kalkan Native profilleri otomasyon için bir DevTools (CDP) uç noktasıyla açılır; Firefox profilleri bu uç nokta olmadan açılır (ws değeri null).

Uç noktalar

Tüm yollar http://127.0.0.1:50360/api/v1 adresine göredir.

İstekNe yapar
GET /statusUygulama ve API durumu: app, version, api, api_allowed, plan, running (açık profil sayısı).
GET /profilesProfilleri listeler. Filtreler: folder, q (arama), tag, engine (profilin bu listede döndürdüğü engine değeri), proxy (yes | no), status (running | used | new | frozen). Sıralama: sort (name | created | last_used | folder | engine | proxy), desc=1. Sayfalama: page, page_size (varsayılan 100, en fazla 500). {total, page, page_size, items} döner.
POST /profilesProfil oluşturur (201). Alanlar: name (zorunlu), engine, os (windows | macos | linux), mode (native | balanced | maximum | gmail | custom; önerilen balanced), folder, tags, notes, start_url, color. Proxy: {type, host, port, username, password} nesnesi (type: http | https | socks5), proxy_user / proxy_pass ile birlikte "socks5://host:port" gibi bir adres ya da pool_id (kayıtlı bir proxy kimliği veya "auto").
GET /profiles/{id}Tek bir profilin tüm ayrıntıları. Proxy şifreleri asla döndürülmez.
PATCH /profiles/{id}name, notes, tags, color, start_url, folder, allow_direct, frozen, extensions, bookmarks, proxy (+ proxy_user, proxy_pass) alanlarını düzenler. Parmak izi ve cihaz alanları değiştirilemez (400).
DELETE /profiles/{id}Profili siler (profil açıkken 409).
POST /profiles/{id}/cloneProfili kopyalar; isteğe bağlı yeni bir name verilebilir (201).
POST /profiles/{id}/startProfili açar. İsteğe bağlı: url, allow_direct, force, cdp (varsayılan true), wait (varsayılan true), saniye cinsinden timeout (5–180, varsayılan 60). id, name, engine, running, already_running, ws, cdp, debug_port, http, pid döner. wait: false ile hemen 202 {starting: true} yanıtı verir.
POST /profiles/{id}/stopProfili kapatır: {stopped}.
GET /profiles/{id}/statusrunning, ws, cdp, debug_port, warnings, errors.
GET /profiles/{id}/cookiesÇerezleri dışa aktarır: ?format=json (varsayılan) ya da netscape. Profil kapalı olmalıdır (aksi halde 409).
POST /profiles/{id}/cookies{cookies: …} alanını JSON listesi ya da Netscape metni olarak içe aktarır ve aktarılan sayıyı döner. Profil kapalı olmalıdır.
PUT /profiles/{id}/proxyProxy'yi ayarlar: kayıtlı proxy için {proxy_id}, yeni proxy için {proxy: {…}}, kaldırmak için {proxy: null}.
GET /runningAçık profiller: [{id, engine, cdp, debug_port, pid}].
POST /stop-allAçık profillerin hepsini kapatır: {stopped: [kimlikler]}.
GET /folders
POST /folders
Klasörleri listeler / {name, color?} ile yeni klasör oluşturur (201).
GET /proxiesKayıtlı proxy'ler (şifreler asla döndürülmez).
POST /proxiesProxy ekler (201): her satırda bir proxy olacak şekilde {text: "…"} ya da {proxies: [...], scheme?, label?}.
DELETE /proxies/{id}Kayıtlı bir proxy'yi siler. Profillere bağlı bir proxy yalnız ?force=true ile silinir (o profiller proxy'siz kalır).
POST /proxies/{id}/checkProxy'yi test eder: çıkış IP'si, ülke, tür, gecikme, tespit sitelerinin neleri görebildiği ve itibar.

Örnekler: curl

PowerShell'de curl.exe yazın; orada curl, Invoke-WebRequest komutunun takma adıdır. JSON gövdeleri Git Bash, cmd ya da bir betikten göndermek en kolayıdır.

curl -H "X-Token: kk_..." http://127.0.0.1:50360/api/v1/status

curl -H "X-Token: kk_..." "http://127.0.0.1:50360/api/v1/profiles?status=running&sort=last_used&desc=1"

curl -X POST -H "X-Token: kk_..." -H "Content-Type: application/json" \
     -d '{"name": "shop-01", "os": "windows", "mode": "balanced", "proxy": "socks5://1.2.3.4:1080", "proxy_user": "user", "proxy_pass": "pass"}' \
     http://127.0.0.1:50360/api/v1/profiles

curl -X POST -H "X-Token: kk_..." -H "Content-Type: application/json" \
     -d '{"url": "https://example.com"}' \
     http://127.0.0.1:50360/api/v1/profiles/PROFILE_ID/start

Örnekler: Python + Playwright

Proxy'li bir profil oluşturur, açar ve connect_over_cdp ile bağlanır (pip install requests playwright).

import requests
from playwright.sync_api import sync_playwright

API = "http://127.0.0.1:50360/api/v1"
H = {"X-Token": "kk_..."}

def call(method, path, **kw):
    r = requests.request(method, API + path, headers=H, timeout=200, **kw).json()
    if not r["ok"]:
        raise RuntimeError(r["error"]["code"] + ": " + r["error"]["message"])
    return r["data"]

prof = call("POST", "/profiles", json={
    "name": "shop-01", "os": "windows", "mode": "balanced",
    "proxy": {"type": "socks5", "host": "1.2.3.4", "port": 1080,
              "username": "user", "password": "pass"},
})
run = call("POST", f"/profiles/{prof['id']}/start")

with sync_playwright() as pw:
    browser = pw.chromium.connect_over_cdp(run["ws"])
    ctx = browser.contexts[0]                  # the profile's own context
    page = ctx.pages[0] if ctx.pages else ctx.new_page()
    page.goto("https://example.com")
    print(page.title())

call("POST", f"/profiles/{prof['id']}/stop")

Örnekler: Node.js + Puppeteer

puppeteer-core kullanın: tarayıcıyı Kalkan başlatır, Puppeteer yalnızca ona bağlanır.

const puppeteer = require("puppeteer-core");

const API = "http://127.0.0.1:50360/api/v1";
const H = { "X-Token": "kk_...", "Content-Type": "application/json" };

(async () => {
  const res = await fetch(`${API}/profiles/PROFILE_ID/start`, { method: "POST", headers: H, body: "{}" });
  const { ok, data, error } = await res.json();
  if (!ok) throw new Error(`${error.code}: ${error.message}`);

  const browser = await puppeteer.connect({ browserWSEndpoint: data.ws, defaultViewport: null });
  const [page] = await browser.pages();
  await page.goto("https://example.com");
  console.log(await page.title());
  await browser.disconnect();
})();

Örnekler: Selenium

Selenium debug_port üzerinden bağlanır. chromedriver'ın ana sürümü tarayıcınınkiyle aynı olmalıdır (Kalkan, bilgisayarınızda kurulu Chrome'u kullanır).

import requests
from selenium import webdriver

API = "http://127.0.0.1:50360/api/v1"
H = {"X-Token": "kk_..."}

run = requests.post(f"{API}/profiles/PROFILE_ID/start", headers=H, json={}).json()["data"]

opts = webdriver.ChromeOptions()
opts.debugger_address = f"127.0.0.1:{run['debug_port']}"
driver = webdriver.Chrome(options=opts)
driver.get("https://example.com")
print(driver.title)

İpuçları

  • Betikten viewport ayarlamayın. Profilin ekran boyutu parmak izinin bir parçasıdır. Puppeteer'da defaultViewport: null kullanın, Playwright'ta viewport vermeyin.
  • Profilin mevcut bağlamını kullanın. Playwright'ta new_context() yerine browser.contexts[0] alın: yeni bir bağlamda profilin çerezleri ve ayarları yoktur.
  • Betiğiniz bitince tarayıcıyı kapatmak yerine bağlantıyı kesin ve profili POST /profiles/{id}/stop ile durdurun; böylece Kalkan oturumu düzgünce kaydeder.
  • Zaten açık bir profili başlatmak aynı uç noktayı already_running: true ile döner; betikler start çağrısını güvenle tekrarlayabilir.
  • 409 yanıtlarını bilinçli ele alın: allow_direct ve force, bir betiğin profili yanlışlıkla proxy'siz ya da yeniden kullanılan bir IP ile açmaması için vardır.