Uygulamanızın sunucusu, kurulum token'ıyla (tcfi_…) Tecof Developer API'sini (/api/v1) kullanır. Kişisel erişim anahtarlarıyla (PAT) aynı uçlar ve aynı yanıt zarfı geçerlidir; fark, token'ın bir kullanıcıya değil bir kuruluma bağlı olması ve mağazanın onayladığı kapsamlarla sınırlanmasıdır.
Base URL: https://api.tecof.com/api/v1
Authorization: Bearer tcfi_...Token almak için bkz. Kimlik Doğrulama → Kurulum token'ı. SDK kullanıyorsanız token yönetimi otomatiktir:
import { tecof } from "@/lib/tecof";
const api = tecof.client(installationId);Yanıt Zarfı#
Tüm uçlar Tecof standart zarfını döner:
{
"success": true,
"message": "İşlem başarılı",
"messageCode": "success",
"data": [],
"totalData": 128
}| Alan | Açıklama |
|---|---|
success | İşlem sonucu |
message | İnsan okur mesaj |
messageCode | Makine okur kod (hata ayrımı için bunu kullanın) |
data | Yük |
totalData | Liste uçlarında toplam kayıt sayısı |
SDK zarfı açar: başarılı çağrı doğrudan data'yı döner; hata durumunda TecofApiError { status, code, data } fırlatır (code = messageCode).
import { TecofApiError } from "@tecof/app-sdk";
try {
const order = await api.orders.get("TCF-1001");
} catch (err) {
if (err instanceof TecofApiError && err.code === "insufficient-scope") {
console.warn("Eksik kapsam:", err.data); // { required, missing }
} else {
throw err;
}
}Sık hata kodları#
| HTTP | messageCode | Ne yapmalı |
|---|---|---|
| 401 | token-expired | Token'ın süresi doldu; yeni token alın (SDK otomatik yeniler) |
| 401 | token-revoked | Token iptal edildi (kaldırma, kapsam değişikliği); yeni token alın, kurulum aktif değilse çağrıyı bırakın |
| 401 | token-invalid | Token tanınmıyor ya da biçimi bozuk |
| 401 | app-suspended | Uygulama Tecof tarafından askıya alındı; token basılmaz |
| 403 | app-token-required | /api/v1/app/* uçları kişisel erişim anahtarıyla (PAT) çağrıldı; bu uçlar yalnız uygulama token'ı kabul eder |
| 403 | insufficient-scope | data: { required, missing }; kapsamı tecof.app.json'a ekleyin, mağaza onaylamalı |
| 404 | not-found | Kayıt yok |
| 429 | rate-limited | Hız sınırı aşıldı; bekleyip yeniden deneyin |
Sayfalama ve Süzgeçler#
| Parametre | Açıklama |
|---|---|
page | 1'den başlar |
limit | En fazla 200; varsayılan 50 (ürün listesi eski sözleşmeyi korur: varsayılan 30) |
updatedSince | ISO 8601; yalnız bu tarihten sonra değişen kayıtlar |
| Kaynağa özel süzgeçler | Aşağıdaki kaynak bölümlerinde |
Tutarlar sayı, tarihler ISO 8601 biçimindedir.
Artımlı senkron örneği — son çalışmadan beri değişen siparişleri sayfa sayfa okur:
import type { TecofApp } from "@tecof/app-sdk";
type ApiClient = ReturnType<TecofApp["client"]>;
export async function syncChangedOrders(api: ApiClient, since: string) {
const limit = 200;
for (let page = 1; ; page++) {
const batch = await api.orders.list({ updatedSince: since, page, limit });
for (const order of batch) {
// siparişi işle
}
if (batch.length < limit) break;
}
}Hız Sınırları#
| Tür | Sınır | Kapsam |
|---|---|---|
| Okuma | 240 istek/dk | Kurulum başına |
| Yazma | 60 istek/dk | Kurulum başına |
Aşımda 429 rate-limited döner. Uygulama token'ında mağazanın paket özelliği kapısı (apiAccess) uygulanmaz.
Siparişler#
| Metot | Uç | Kapsam |
|---|---|---|
GET | /api/v1/orders | orders:read |
GET | /api/v1/orders/:idOrNumber | orders:read |
Liste süzgeçleri: status, paymentStatus, search, createdFrom, createdTo, updatedSince. Tek sipariş uçu kimlik ya da sipariş numarası (TCF-1001) kabul eder.
curl "https://api.tecof.com/api/v1/orders?paymentStatus=paid&limit=20" \
-H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN"const paid = await api.orders.list({ paymentStatus: "paid", limit: 20 });
const order = await api.orders.get("TCF-1001");Sipariş nesnesi:
{
"id": "6720bb00cc11dd22ee33ff44",
"orderNumber": "TCF-1001",
"status": "confirmed",
"paymentStatus": "paid",
"currency": "TRY",
"orderedAt": "2026-10-10T09:15:00.000Z",
"createdAt": "2026-10-10T09:15:00.000Z",
"updatedAt": "2026-10-10T09:16:12.000Z",
"cancelledAt": null,
"cancelReason": null,
"customer": {
"id": "66f1aa00bb11cc22dd33ee77",
"firstName": "Örnek",
"lastName": "Müşteri",
"email": "musteri@example.com",
"phone": "+905550000000"
},
"billingAddress": {
"firstName": "Örnek", "lastName": "Müşteri", "company": "", "phone": "+905550000000",
"email": "musteri@example.com", "country": "TR", "city": "İstanbul", "district": "Kadıköy",
"zip": "34000", "line1": "Örnek Mah. Deneme Sk. No: 1", "line2": "", "identityNumber": "11111111111",
"invoiceType": "individual", "taxNumber": "", "taxOffice": ""
},
"shippingAddress": {
"firstName": "Örnek", "lastName": "Müşteri", "company": "", "phone": "+905550000000",
"email": "musteri@example.com", "country": "TR", "city": "İstanbul", "district": "Kadıköy",
"zip": "34000", "line1": "Örnek Mah. Deneme Sk. No: 1", "line2": "", "identityNumber": "",
"invoiceType": "individual", "taxNumber": "", "taxOffice": ""
},
"lineItems": [
{
"id": "li_1", "productId": "66f2aa00bb11cc22dd33ee88", "variantId": "66f2aa00bb11cc22dd33ee99",
"name": "Pamuklu Tişört", "variantTitle": "S / Siyah", "sku": "TS-S",
"quantity": 2, "unitPrice": 500, "totalPrice": 1000,
"taxRate": 20, "taxAmount": 166.67, "discountAmount": 0, "netTotal": 833.33, "taxIncluded": true,
"personalizationTotal": 0
}
],
"shippingLines": [
{ "title": "Standart Kargo", "carrier": "Örnek Kargo", "deliveryMethod": "standard", "price": 50 }
],
"discountLines": [],
"totals": {
"subtotal": 1000, "discount": 0, "shipping": 50, "paymentFee": 0,
"tax": 175, "taxAddedToTotal": 0, "total": 1050,
"pricesIncludeTax": true, "shippingTaxRate": 20, "shippingTaxAmount": 8.33, "shippingTaxIncluded": true
},
"payment": {
"provider": "iyzico", "paidAmount": 1050, "paidAt": "2026-10-10T09:16:10.000Z",
"installmentCount": 1, "cardAssociation": "VISA", "lastFourDigits": "0000"
},
"packages": [],
"note": "",
"tags": [],
"salesChannelId": null
}- Fatura kimliği (
billingAddress):invoiceType"individual"ya da"corporate". Kurumsaldacompanyunvan,taxNumbervergi numarası,taxOfficevergi dairesidir. Türkiye'detaxNumber10 haneli VKN (sağlama hanesi doğrulanmış) ya da şahıs şirketi için 11 haneli TCKN olur; yurt dışı kurumsal alıcıda serbest biçimlidir ve vergi dairesi boş olabilir. Bireysel alıcıda bu iki alan boştur, kimlikidentityNumber'dadır (anonim alıcı11111111111). Ayrıntı ve hazır sınıflandırma için Fatura Uygulamaları. lineItems[].discountAmount: satıra düşen sipariş indirimi, satırın kendi KDV modunda (hediye çeki hariç). Satırların toplamıtotals.discounta eşittir.netTotalvetaxAmountindirim sonrası matrahı ve KDV'yi verir: KDV, indirim düşüldükten sonra kalan tutar üzerinden hesaplanır. Kapsamlı kupon yalnız kendi satırlarının matrahını düşürür. 10.10.2026 öncesi siparişlerdediscountAmount0'dır ve KDV indirim öncesi tutardan hesaplanmıştır.lineItems[].taxRatenullise kayıt eski bir siparişe aittir ve oran bilinmez; fatura uygulamaları mağaza varsayılan oranına düşmelidir.packages[]:{ id, trackingNumber, carrier, status, items: [{ lineItemId, quantity }], shippedAt, deliveredAt }.discountLines[]:{ source, title, amount }.
Müşteriler#
| Metot | Uç | Kapsam |
|---|---|---|
GET | /api/v1/customers | customers:read |
GET | /api/v1/customers/:id | customers:read |
Liste süzgeçleri: search, updatedSince.
const customers = await api.customers.list({ search: "musteri@example.com" });
const customer = await api.customers.get("66f1aa00bb11cc22dd33ee77");{
"id": "66f1aa00bb11cc22dd33ee77",
"firstName": "Örnek", "lastName": "Müşteri", "fullName": "Örnek Müşteri",
"email": "musteri@example.com", "phone": "+905550000000",
"accountStatus": "active", "isEmailVerified": true, "preferredLanguage": "tr",
"groupIds": [], "tagIds": [], "note": "",
"addresses": [
{
"id": "addr_1", "title": "Ev", "firstName": "Örnek", "lastName": "Müşteri",
"phone": "+905550000000", "country": "TR", "city": "İstanbul", "district": "Kadıköy",
"zip": "34000", "line1": "Örnek Mah. Deneme Sk. No: 1", "line2": "", "isDefault": true
}
],
"totalOrders": 3, "totalSpent": 2450, "firstOrderAt": "2026-08-01T10:00:00.000Z",
"lastOrderAt": "2026-10-10T09:15:00.000Z",
"createdAt": "2026-08-01T09:58:00.000Z", "updatedAt": "2026-10-10T09:15:00.000Z"
}Parola ve token alanları hiçbir koşulda dönmez.
Envanter#
| Metot | Uç | Kapsam |
|---|---|---|
GET | /api/v1/inventory | products:read |
Süzgeçler: sku, productId, lowStock, updatedSince. Her satır bir varyanttır:
{
"productId": "66f2aa00bb11cc22dd33ee88",
"productName": "Pamuklu Tişört",
"productSlug": "pamuklu-tisort",
"variantId": "66f2aa00bb11cc22dd33ee99",
"sku": "TS-S",
"barcode": "8690000000000",
"title": "S / Siyah",
"price": 500,
"stock": 12,
"locations": [{ "locationId": "66f3aa00bb11cc22dd33ee00", "name": "Ana Depo", "quantity": 12 }],
"updatedAt": "2026-10-10T08:00:00.000Z"
}const lowStock = await api.inventory.list({ lowStock: true });Stok yazma Tools API üzerinden yapılır (apply_stock_count, products:write) — aşağıya bakın.
Ürünler#
| Metot | Uç | Kapsam |
|---|---|---|
GET | /api/v1/products | products:read |
GET | /api/v1/products/:idOrSlug | products:read |
POST | /api/v1/products | products:write (upsert) |
PATCH | /api/v1/products/:id | products:write |
Ürün uçları mevcut Developer API ürün sözleşmesini kullanır: liste hafiftir (fields=full ile açıklama ve varyantlar gelir), :idOrSlug kimlik, slug ya da varyant SKU'su kabul eder, çok dilli alanlar [{ code, value }] biçimindedir. Ürün listesinde süzgeçler: search, status, category, brand, tag, updatedSince, fields=full. Ürün listesinin varsayılan limit değeri 30'dur (en fazla 200). Ürün nesneleri kimliği _id alanında taşır (sipariş, müşteri ve envanterde id).
const products = await api.products.list({ status: "active", limit: 50 });
const product = await api.products.get("pamuklu-tisort");{
"_id": "66f2aa00bb11cc22dd33ee88",
"slug": "pamuklu-tisort",
"name": [{ "code": "tr", "value": "Pamuklu Tişört" }],
"status": "active",
"type": "variable",
"totalStock": 12,
"variantCount": 2,
"variants": [
{
"_id": "66f2aa00bb11cc22dd33ee99", "sku": "TS-S", "barcode": null,
"price": 500, "compareAtPrice": 650, "weight": 300, "isActive": true,
"stock": 12, "stocks": [{ "stockLocationId": "66f3aa00bb11cc22dd33ee00", "quantity": 12 }],
"variantValues": [{ "variantTypeId": "…", "variantValueId": "…" }]
}
]
}Ürün yazma anında canlıdır:
status: "active"gönderilen ürün vitrine çıkar. Ürün yazma ayrıca mağaza paketinde e-ticaretin açık olmasını ister (403 plan-feature-unavailable).
Yazma İşlemleri: Tools API#
Okuma dışındaki işlemler (stok sayımı uygulama gibi) Tecof'un tek araç kayıt defteri üzerinden, Tools API ile yapılır. Aynı araçlar MCP sunucusunda da kullanılır. Uygulama token'ı api yüzeyindeki araçları, mağazanın verdiği kapsamlarla görür ve çalıştırır.
| Metot | Uç | Açıklama |
|---|---|---|
GET | /api/v1/tools?surface=api | Araç kataloğu (ad, açıklama, JSON Schema girdi, gereken kapsamlar, onay ve kredi bilgisi) |
GET | /api/v1/tools/:name | Tek aracın tanımı |
POST | /api/v1/tools/:name | Aracı çalıştırır; gövde = araç girdisi (JSON) |
Her aracın girdi şeması katalogda inputSchema olarak yayımlanır. Çağırmadan önce şemayı okuyun:
curl "https://api.tecof.com/api/v1/tools/apply_stock_count" \
-H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN"// Girdi alanlarını aracın inputSchema'sına göre doldurun
const result = await api.tools.call("apply_stock_count", input);Ham HTTP ile çalıştırma:
curl -X POST "https://api.tecof.com/api/v1/tools/apply_stock_count" \
-H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: stock-sync-2026-10-10-0001" \
-d @input.json| Konu | Davranış |
|---|---|
| Kapsam | Araç başına denetlenir: 403 insufficient-scope { required, missing } |
| Doğrulama | 400 validation-error { issues: [{ path, message }] } |
Idempotency-Key | İsteğe bağlı (≤128 karakter). Aynı anahtar + aynı girdi → saklanan yanıt (Idempotency-Replayed: true); farklı girdi → 422 idempotency-key-reused; işlem sürerken → 409 idempotency-in-progress. Saklama 24 saat |
| Onay isteyen araçlar | İlk çağrı 409 confirmation-required { needsConfirmation, confirmId, summary, expiresAt } döner; aynı girdiyle confirm: true ve confirmId ekleyerek yeniden çağırın (aşağıda) |
| Hız sınırı | 429 rate-limited + Retry-After: 60 |
| Akış | ?stream=1 ile text/event-stream (ilerleme + sonuç çerçeveleri) |
Onay isteyen araçlar#
Silme ya da canlıyı doğrudan değiştiren araçlar iki adımda çalışır. Uygulama token'ında da akış kişisel erişim anahtarıyla aynıdır: onayı sizin uygulamanız verir (gerekirse kullanıcıya App Bridge confirm ile sorarak).
import { TecofApiError } from "@tecof/app-sdk";
async function callWithConfirm(api: ApiClient, name: string, input: Record<string, unknown>) {
try {
return await api.tools.call(name, input);
} catch (err) {
if (err instanceof TecofApiError && err.code === "confirmation-required") {
const { confirmId, summary } = err.data as { confirmId: string; summary: string };
// summary'yi kaydedin ya da kullanıcıya gösterin; onaylandıysa aynı girdiyle tekrar çağırın
return api.tools.call(name, { ...input, confirm: true, confirmId });
}
throw err;
}
}confirmId süresi dolmuşsa 409 confirmation-expired döner; confirmId olmadan baştan çağırın.
Uygulamaya Özel Uçlar#
Bu uçlar yalnız uygulama token'ıyla çalışır ve kapsam istemez (metafield'lar hariç); veri kuruluma aittir. Kişisel erişim anahtarıyla (PAT) /api/v1/app/* çağrısı 403 app-token-required döner.
| Metot | Uç | Açıklama | SDK |
|---|---|---|---|
GET | /api/v1/app/installation | Kurulumun kendisi | api.installation() |
GET | /api/v1/app/settings | Ayarlar | api.settings.get() |
PUT | /api/v1/app/settings | Ayar yazma | api.settings.set(obj, { merge }) |
GET | /api/v1/app/secrets | Sır listesi (değer yok) | api.secrets.list() |
GET | /api/v1/app/secrets/:key | Sır okuma | api.secrets.get(key) |
PUT | /api/v1/app/secrets/:key | Sır yazma | api.secrets.set(key, value) |
DELETE | /api/v1/app/secrets/:key | Sır silme | api.secrets.delete(key) |
POST | /api/v1/app/events | Uygulama olayı yayınlama | api.events.publish(name, data) |
GET | /api/v1/app/events/catalog | Mağazadaki uygulama olayları | api.events.catalog() |
GET | /api/v1/metafields | Metafield listesi | api.metafields.list({...}) |
PUT | /api/v1/metafields | Metafield yazma | api.metafields.set({...}) |
DELETE | /api/v1/metafields/:id | Metafield silme | api.metafields.delete(id) |
Kurulum#
const installation = await api.installation();{
"installationId": "6720aa00bb11cc22dd33ee55",
"status": "active",
"installedAt": "2026-10-10T08:00:00.000Z",
"isTestInstall": false,
"scopes": ["orders:read", "customers:read", "products:read"],
"pendingScopes": [],
"merchant": {
"id": "66f0c0ffee0000000000abcd", "name": "Örnek Mağaza", "productType": "ecommerce",
"languages": ["tr", "en"], "defaultLanguage": "tr", "currency": "TRY"
},
"app": { "clientId": "tcfa_xxxxxxxxxxxxxxxx", "slug": "isbasi", "name": "Logo İşbaşı", "configVersion": 3 },
"subscription": { "planKey": "standart", "status": "active", "trialEndsAt": null, "currentPeriodEnd": "2026-11-10T09:16:10.000Z" }
}isTestInstall: true, kurulumun uygulamanın test mağazalarından birinde olduğunu gösterir. Plan yoksa subscription null olur. pendingScopes, mağazanın henüz onaylamadığı kapsam artışıdır.
Ayarlar#
curl "https://api.tecof.com/api/v1/app/settings" -H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN"{ "success": true, "messageCode": "success", "data": { "settings": { "invoiceMode": "draft" }, "updatedAt": "2026-10-10T09:00:00.000Z" } }curl -X PUT "https://api.tecof.com/api/v1/app/settings" \
-H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "settings": { "invoiceMode": "issued" }, "merge": true }'Yanıt: { settings, updatedAt }. Sır olmayan JSON, en fazla 64 KB. merge: true mevcut nesneyle birleştirir. API'den ayar yazmak app.settings.updated olayı üretmez (olay yalnız panel formu kaydında gelir).
Sırlar (Vault)#
# Yazma
curl -X PUT "https://api.tecof.com/api/v1/app/secrets/isbasiApiKey" \
-H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "value": "örnek-api-anahtarı" }'
# → { "data": { "key": "isbasiApiKey", "updatedAt": "…" } }
# Listeleme (değer dönmez)
curl "https://api.tecof.com/api/v1/app/secrets" -H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN"
# → { "data": [ { "key": "isbasiApiKey", "updatedAt": "…", "lastReadAt": "…", "length": 18 } ] }
# Okuma
curl "https://api.tecof.com/api/v1/app/secrets/isbasiApiKey" -H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN"
# → { "data": { "key": "isbasiApiKey", "value": "örnek-api-anahtarı", "updatedAt": "…" } }Kurallar ve şifreleme tasarımı: Ayarlar, Vault ve Metafield'lar.
Metafield'lar#
curl -X PUT "https://api.tecof.com/api/v1/metafields" \
-H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ownerType": "order",
"ownerId": "6720bb00cc11dd22ee33ff44",
"key": "invoiceNumber",
"type": "string",
"value": "ABC2026000000123",
"visibility": "shared",
"panel": { "label": { "tr": "İşbaşı fatura no", "en": "İşbaşı invoice no" }, "show": true }
}'
curl "https://api.tecof.com/api/v1/metafields?ownerType=order&ownerId=6720bb00cc11dd22ee33ff44&namespace=isbasi" \
-H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN"PUT yanıtı:
{
"id": "6720ee00ff11aa22bb33cc77",
"namespace": "isbasi",
"ownerType": "order",
"ownerId": "6720bb00cc11dd22ee33ff44",
"key": "invoiceNumber",
"type": "string",
"value": "ABC2026000000123",
"visibility": "shared",
"panel": { "label": { "tr": "İşbaşı fatura no", "en": "İşbaşı invoice no" }, "show": true },
"own": true,
"updatedAt": "2026-10-10T09:20:00.000Z"
}own, kaydın çağıran uygulamanın namespace'ine ait olup olmadığını gösterir. ownerType: "merchant" için ownerId yok sayılır (kayıt mağazaya bağlanır).
Uygulama olayları#
curl -X POST "https://api.tecof.com/api/v1/app/events" \
-H "Authorization: Bearer $TECOF_INSTALLATION_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "invoice.created", "data": { "orderId": "6720bb00cc11dd22ee33ff44", "invoiceNumber": "ABC2026000000123" } }'Mağazadaki diğer uygulamaların yayınladığı olaylar:
const catalog = await api.events.catalog();
// [{ slug: "kargo", appName: "Örnek Kargo", event: "app.kargo.shipment.created", description: { tr: "…", en: "…" } }]Ayrıntılar: Uygulamalar Arası İletişim.