TN.TC API
QR, link, Box, Chat, Bell, site ve Hub işlemlerini API ile yönet. Her istek hesabının yetki ve kullanım sınırlarına tabidir.
https://tn.tc/api/v1OpenAPI 3.1OpenAPI 3.1, API’nin makinece okunan tam tanımıdır: Postman, Insomnia veya kod üreticilere yükleyip istemci oluşturabilirsin. Dosya olarak iner.
Kimlik doğrulama
Taban adres /api/v1. Her istekte Authorization: Bearer tntc_sk_… başlığı gönder.
- Anahtar, bir çalışma alanına ve oluşturan kişinin güncel rolüne bağlıdır; seçilen kapsamların dışına çıkamaz.
- Web oturumu ve mobil erişim belirteci ayrı kimliklerdir; anahtar onların yerine geçmez.
- Anahtarı tarayıcı koduna, mobil uygulamaya, URL'ye veya log'a koyma. Sızarsa hemen iptal et veya döndür.
Kapsamlar
Her uç nokta bir kapsam ister; kaynak uç noktaları (/resources) kaydın türüne göre qr, links, box veya sites kapsamını kontrol eder. OpenAPI belgesinde her işlemin x-tntc-key-scope değeri vardır.
Hesap ve kullanım
profile:read- Profil, çalışma alanları, ekip listesi
profile:write- Profil ve bildirim okundu bilgisi
usage:read- Paket kapasitesi ve kullanım
billing:read- Paket durumunu oku
QR
qr:read- QR kodlarını oku, SVG al
qr:write- QR oluştur, düzenle, arşivle
analytics:read- Tarama ve ziyaret istatistikleri
Link ve adres
links:read- Linkleri ve adres uygunluğunu oku
links:write- Link oluştur, düzenle, arşivle
Box ve dosyalar
box:read- Box, politika ve gönderimleri oku
box:write- Box oluştur, politika ve incelemeyi yönet
files:read- Dosya bilgisi ve izinli indirme
files:write- Yükleme başlat/tamamla, dosya yönet
Chat ve Bell
chat:read- Sohbetler, mesajlar, canlı akış
chat:write- Mesaj gönder, düzenle, tepki ver
bell:read- Bell siparişleri ve durumları
bell:write- Bell teklif ayarları ve sipariş başlatma
Mini site
sites:read- Siteleri, menüleri, şablonları ve sürümleri oku
sites:write- Site/menü oluştur; sosyal link, görsel ve tasarımı düzenle
sites:publish- Yayınla
leads:read- İzinli müşteri listesini oku ve dışa aktar (sahip/yönetici)
leads:write- İzni geri çek veya kişileri sil (sahip/yönetici)
Ürünler ve kurslar
commerce:read- Ürünleri, izinli siparişleri ve satın alınan içeriği oku
commerce:write- Ürün ve kurs taslaklarını yönet (tahsilat/iade yetkisi vermez)
UGC
ugc:read- Creator, kampanya, başvuru oku
ugc:write- Kampanya ve başvuru işlemleri
earnings:read- Kazançları oku (ödeme yok)
Anahtarla yapılamayanlar: hesap silme ve dışa aktarma, ödeme başlatma, kazanç ödemesi, ekip yönetimi, anahtar ve webhook yönetimi, platform yönetimi.
Hatalar
Hatalar kararlı bir makine kodu ve destekte kullanabileceğin bir requestId döndürür.
{ "error": { "code": "insufficient_scope", "requestId": "…" } }| HTTP | code |
|---|---|
| 400/422 | invalid_input |
| 401 | unauthorized |
| 403 | insufficient_scope · forbidden · quota_exceeded |
| 404 | not_found |
| 409 | conflict · idempotency_conflict · idempotency_in_progress |
| 413 | invalid_input |
| 429 | rate_limited (Retry-After) |
| 503 | configuration_missing |
Tekrar güvenli istekler
POST, PATCH ve DELETE isteklerine Idempotency-Key ekle. Aynı anahtar ve gövde 24 saat içinde ilk yanıtı döndürür (Idempotent-Replayed: true); farklı gövde 409 idempotency_conflict alır; ilk istek sürerken 409 idempotency_in_progress döner.
Limitler
- Free
- 10/ dk
- Pro
- 60/ dk
Anahtar başına dakikada istek: Ücretsiz 10, Pro 60. Aşılırsa 429 ve Retry-After döner. Oluşturduğun kaynaklar paketinin kaynak, depolama ve Box kotasından düşer.
Paket sayıları geçicidir ve ticari teklif değildir; hız limiti bir SLA değildir.
Webhook'lar
Gövde: id, type, schemaVersion, occurredAt, workspaceId, data. Başlıklar: TNTC-Event-Id, TNTC-Event-Type, TNTC-Delivery-Attempt, TNTC-Signature (t=zaman damgası, v1=HMAC-SHA256(secret, t + '.' + ham gövde)). Beş dakikadan eski imzaları reddet.
resource.created- QR, link, Box veya site oluşturuldu
resource.updated- Kaynak değişti (sürüm artar)
resource.archived- Kaynak arşivlendi
qr.import.completed- QR aktarımı tamamlandı (yalnız sayılar ve iş kimliği)
links.import.completed- Link aktarımı tamamlandı (yalnız sayılar ve iş kimliği)
box.submission.completed- Box isteğine dosya geldi
file.ready- Dosya kullanıma hazır ya da yeni sürümü var
chat.message.created- Yeni mesaj (yalnız kimlikler; içerik yok)
chat.conversation.updated- Grup/kanal ayarı veya üyelik yönetimi değişti
bell.order.updated- Bell sipariş durumu değişti
site.published- Mini site yayınlandı
menu.published- Menü yayınlandı (fiyat/ürün değişikliği)
quote.received- Siteden teklif talebi geldi (yalnız kimlikler)
quote.updated- Teklif talebinin durumu veya brief Box’ı değişti
commerce.product.updated- Ürün değişti
commerce.order.updated- Sipariş değişti (yalnız kimlik ve işlem)
ugc.application.updated- UGC başvurusu değişti
lead.confirmed- E-posta kaydı doğrulandı (yalnız kimlikler)
lead.unsubscribed- Kişi e-posta iznini geri çekti (yalnız kimlikler)
import { createHmac, timingSafeEqual } from 'node:crypto';
// header: TNTC-Signature: t=<unix seconds>,v1=<hex>[,v1=<hex during rotation>]
export function verifyTntcSignature(secret: string, header: string, rawBody: string) {
const parts = header.split(',');
const t = Number(parts.find((p) => p.startsWith('t='))?.slice(2));
if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
return parts
.filter((p) => p.startsWith('v1='))
.some((p) => {
const given = Buffer.from(p.slice(3), 'hex');
return given.length === expected.length && timingSafeEqual(given, expected);
});
}
// Deliveries are at least once: store TNTC-Event-Id and ignore repeats.Örnekler
curl -sS "https://tn.tc/api/v1/resources?kind=qr&limit=5" \
-H "Authorization: Bearer $TNTC_API_KEY"curl -sS -X POST "https://tn.tc/api/v1/resources" \
-H "Authorization: Bearer $TNTC_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: menu-qr-2026-09-25" \
-d '{"kind":"qr","name":"Menu QR","qrType":"website","targetUrl":"https://example.com/menu"}'const api = 'https://tn.tc/api/v1';
const headers = {
Authorization: `Bearer ${process.env.TNTC_API_KEY}`,
'Content-Type': 'application/json',
};
// Retry-safe create: the same Idempotency-Key returns the first result.
const created = await fetch(`${api}/resources`, {
method: 'POST',
headers: { ...headers, 'Idempotency-Key': crypto.randomUUID() },
body: JSON.stringify({ kind: 'qr', name: 'Menu QR', qrType: 'website', targetUrl: 'https://example.com/menu' }),
});
if (!created.ok) throw new Error((await created.json()).error.code);
const qr = await created.json();
// Change the destination later; the printed QR keeps working.
await fetch(`${api}/resources/${qr.id}`, {
method: 'PATCH',
headers,
body: JSON.stringify({ targetUrl: 'https://example.com/menu-autumn' }),
});