ℹ Language notice: Developer documentation on this page is currently maintained in Turkish. Code samples, HTTP headers and URLs are language-neutral; narrative sections will be translated to English. If you need help right now, email admin@teknikdanisman.net.

Examples

Copy-paste ready snippets for cURL, Node.js, Python, PHP and Go. Every example reads TD_API_KEY from the environment — never commit keys.

Müşteri listesi (pagination)

Ilk sayfayı çek, sonraki cursor varsa devam et.

curl -s 'https://teknikdanisman.net/api/v1/customers.php?limit=25' \
  -H 'Authorization: Bearer tdk_...' | jq
const res = await fetch('https://teknikdanisman.net/api/v1/customers.php?limit=25', {
  headers: { Authorization: `Bearer ${process.env.TD_API_KEY}` },
});
const { data, has_more, next_cursor } = await res.json();
console.log(`${data.length} müşteri çekildi, devamı: ${has_more ? next_cursor : 'yok'}`);
import os, requests
r = requests.get(
    'https://teknikdanisman.net/api/v1/customers.php',
    params={'limit': 25},
    headers={'Authorization': f'Bearer {os.environ["TD_API_KEY"]}'},
)
r.raise_for_status()
body = r.json()
print(f"{len(body['data'])} müşteri, devamı: {body.get('next_cursor')}")
$ch = curl_init('https://teknikdanisman.net/api/v1/customers.php?limit=25');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('TD_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
echo count($body['data']) . " müşteri çekildi\n";
req, _ := http.NewRequest("GET", "https://teknikdanisman.net/api/v1/customers.php?limit=25", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("TD_API_KEY"))
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var body struct {
    Data       []map[string]any `json:"data"`
    HasMore    bool             `json:"has_more"`
    NextCursor *int             `json:"next_cursor"`
}
json.NewDecoder(resp.Body).Decode(&body)
fmt.Printf("%d müşteri\n", len(body.Data))

Yeni employees oluştur

Idempotency-Key ile network retry güvenli POST.

curl -s -X POST 'https://teknikdanisman.net/api/v1/employees.php' \
  -H 'Authorization: Bearer tdk_...' \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "customer_id": 12,
    "name": "Ayşe Yılmaz",
    "role": "Muhasebe",
    "email": "ayse@firma.com",
    "hire_date": "2026-06-01"
  }' | jq
import { randomUUID } from 'node:crypto';

const res = await fetch('https://teknikdanisman.net/api/v1/employees.php', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TD_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': randomUUID(),
  },
  body: JSON.stringify({
    customer_id: 12,
    name: 'Ayşe Yılmaz',
    role: 'Muhasebe',
    email: 'ayse@firma.com',
    hire_date: '2026-06-01',
  }),
});
if (res.status === 422) {
  const { errors } = await res.json();
  console.error('Validation hataları:', errors);
} else {
  console.log('Oluştu:', await res.json());
}
import os, uuid, requests
r = requests.post(
    'https://teknikdanisman.net/api/v1/employees.php',
    headers={
        'Authorization': f'Bearer {os.environ["TD_API_KEY"]}',
        'Idempotency-Key': str(uuid.uuid4()),
    },
    json={
        'customer_id': 12,
        'name': 'Ayşe Yılmaz',
        'role': 'Muhasebe',
        'email': 'ayse@firma.com',
        'hire_date': '2026-06-01',
    },
    timeout=10,
)
if r.status_code == 422:
    print('Validation hataları:', r.json()['errors'])
else:
    r.raise_for_status()
    print('Oluştu:', r.json())
$payload = [
    'customer_id' => 12,
    'name' => 'Ayşe Yılmaz',
    'role' => 'Muhasebe',
    'email' => 'ayse@firma.com',
    'hire_date' => '2026-06-01',
];
$ch = curl_init('https://teknikdanisman.net/api/v1/employees.php');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('TD_API_KEY'),
        'Content-Type: application/json',
        'Idempotency-Key: ' . bin2hex(random_bytes(16)),
    ],
]);
$res = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$body = json_decode($res, true);
if ($code === 422) print_r($body['errors']); else print_r($body);
payload := map[string]any{
    "customer_id": 12,
    "name":        "Ayşe Yılmaz",
    "role":        "Muhasebe",
    "email":       "ayse@firma.com",
    "hire_date":   "2026-06-01",
}
b, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://teknikdanisman.net/api/v1/employees.php", bytes.NewReader(b))
req.Header.Set("Authorization", "Bearer "+os.Getenv("TD_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.New().String())
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body)

Service veya lisans yenile (+1 yıl)

Domain/hosting/SSL servisi ya da yazılım lisansının yenileme tarihini ileri al.

curl -s -X POST 'https://teknikdanisman.net/api/v1/renew.php' \
  -H 'Authorization: Bearer tdk_...' \
  -H 'Content-Type: application/json' \
  -d '{"resource":"service","id":42}' | jq
const res = await fetch('https://teknikdanisman.net/api/v1/renew.php', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TD_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ resource: 'service', id: 42 }),
});
const { data } = await res.json();
console.log(`Updatenen kolonlar: ${data.updated_columns.join(', ')}`);
import os, requests
r = requests.post(
    'https://teknikdanisman.net/api/v1/renew.php',
    headers={'Authorization': f'Bearer {os.environ["TD_API_KEY"]}'},
    json={'resource': 'service', 'id': 42},
)
print(r.json()['data']['updated_columns'])
$ch = curl_init('https://teknikdanisman.net/api/v1/renew.php');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode(['resource' => 'service', 'id' => 42]),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('TD_API_KEY'),
        'Content-Type: application/json',
    ],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($body['data']);
b, _ := json.Marshal(map[string]any{"resource": "service", "id": 42})
req, _ := http.NewRequest("POST", "https://teknikdanisman.net/api/v1/renew.php", bytes.NewReader(b))
req.Header.Set("Authorization", "Bearer "+os.Getenv("TD_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body)

Webhook imza doğrulama (receiver)

Express/Flask/Slim handler — HMAC-SHA256 ile gelen X-TD-Signature'ı timing-safe karşılaştırır.

# Bu sizin receiver endpoint'iniz — request gelir, doğrularsınız.
# Aşağıdaki dil örneklerine bakın.
import express from 'express';
import crypto from 'crypto';

const app = express();
const SECRET = process.env.TD_WEBHOOK_SECRET;

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.header('X-TD-Signature') || '';
  const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(req.body).digest('hex');
  if (sig.length !== expected.length ||
      !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).send('bad signature');
  }
  const event = JSON.parse(req.body.toString());
  console.log(`Olay: ${event.event} (tenant ${event.tenant_id})`);
  res.json({ ok: true });
});

app.listen(3000);
import os, hmac, hashlib
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ['TD_WEBHOOK_SECRET'].encode()

@app.post('/webhook')
def webhook():
    sig = request.headers.get('X-TD-Signature', '')
    expected = 'sha256=' + hmac.new(SECRET, request.data, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        abort(401)
    event = request.get_json()
    print(f"Olay: {event['event']} (tenant {event['tenant_id']})")
    return {'ok': True}
$secret = getenv('TD_WEBHOOK_SECRET');
$body   = file_get_contents('php://input');
$sig    = $_SERVER['HTTP_X_TD_SIGNATURE'] ?? '';
$expect = 'sha256=' . hash_hmac('sha256', $body, $secret);

if (!hash_equals($expect, $sig)) {
    http_response_code(401);
    exit('bad signature');
}

$event = json_decode($body, true);
file_put_contents('webhook.log', $event['event'] . " tenant=" . $event['tenant_id'] . "\n", FILE_APPEND);
echo json_encode(['ok' => true]);
http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    secret := []byte(os.Getenv("TD_WEBHOOK_SECRET"))
    mac := hmac.New(sha256.New, secret)
    mac.Write(body)
    expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
    sig := r.Header.Get("X-TD-Signature")
    if !hmac.Equal([]byte(expected), []byte(sig)) {
        http.Error(w, "bad signature", http.StatusUnauthorized)
        return
    }
    var event map[string]any
    json.Unmarshal(body, &event)
    log.Printf("Olay: %v (tenant %v)", event["event"], event["tenant_id"])
    w.Write([]byte(`{"ok":true}`))
})

Tüm sayfaları gezerek toplam

Cursor-based pagination ile rate-limit'e takılmadan tüm kayıtları çek.

# Loop curl'da pratik değil — Node/Python örneğine bakın.
async function fetchAll(url, key) {
  const all = [];
  let cursor = null;
  while (true) {
    const u = new URL(url);
    u.searchParams.set('limit', '100');
    if (cursor) u.searchParams.set('cursor', cursor);
    const r = await fetch(u, { headers: { Authorization: `Bearer ${key}` } });
    if (r.status === 429) {
      await new Promise(s => setTimeout(s, (+r.headers.get('Retry-After') || 60) * 1000));
      continue;
    }
    const { data, has_more, next_cursor } = await r.json();
    all.push(...data);
    if (!has_more) return all;
    cursor = next_cursor;
  }
}

const customers = await fetchAll('https://teknikdanisman.net/api/v1/customers.php', process.env.TD_API_KEY);
console.log(`Total ${customers.length} müşteri`);
import os, time, requests

def fetch_all(url, key):
    out, cursor = [], None
    while True:
        params = {'limit': 100}
        if cursor: params['cursor'] = cursor
        r = requests.get(url, params=params, headers={'Authorization': f'Bearer {key}'})
        if r.status_code == 429:
            time.sleep(int(r.headers.get('Retry-After', 60)))
            continue
        r.raise_for_status()
        body = r.json()
        out.extend(body['data'])
        if not body['has_more']: return out
        cursor = body['next_cursor']

customers = fetch_all('https://teknikdanisman.net/api/v1/customers.php', os.environ['TD_API_KEY'])
print(f"Total {len(customers)} müşteri")
function fetch_all(string $url, string $key): array {
    $all = []; $cursor = null;
    while (true) {
        $u = $url . '?limit=100' . ($cursor ? '&cursor=' . $cursor : '');
        $ch = curl_init($u);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER => true,
            CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key],
        ]);
        $resp = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $hdrSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        curl_close($ch);
        if ($code === 429) { sleep(60); continue; }
        $body = json_decode(substr($resp, $hdrSize), true);
        $all = array_merge($all, $body['data']);
        if (!$body['has_more']) return $all;
        $cursor = $body['next_cursor'];
    }
}

$customers = fetch_all('https://teknikdanisman.net/api/v1/customers.php', getenv('TD_API_KEY'));
echo "Total " . count($customers) . " müşteri\n";
func fetchAll(url, key string) ([]map[string]any, error) {
    var all []map[string]any
    cursor := ""
    for {
        u := url + "?limit=100"
        if cursor != "" { u += "&cursor=" + cursor }
        req, _ := http.NewRequest("GET", u, nil)
        req.Header.Set("Authorization", "Bearer "+key)
        resp, err := http.DefaultClient.Do(req)
        if err != nil { return nil, err }
        if resp.StatusCode == 429 {
            time.Sleep(60 * time.Second)
            resp.Body.Close()
            continue
        }
        var body struct {
            Data       []map[string]any `json:"data"`
            HasMore    bool             `json:"has_more"`
            NextCursor *int             `json:"next_cursor"`
        }
        json.NewDecoder(resp.Body).Decode(&body)
        resp.Body.Close()
        all = append(all, body.Data...)
        if !body.HasMore { return all, nil }
        cursor = fmt.Sprint(*body.NextCursor)
    }
}

Daha fazlası

Tüm endpoint'ler, request/response şemaları ve query parametreleri için OpenAPI referansı; tek tıkla deneme için Postman collection. Hata kodları → Error reference.