Aynı mağazada kurulu uygulamalar birbirleriyle gevşek bağlı biçimde çalışabilir: bir uygulama olay yayınlar, diğeri abone olur; bir uygulama kaynağa veri yazar, diğeri okur. Mağazanın onayı kurulumla örtüktür: iki uygulama da mağazada kuruluysa ve olaylar yapılandırmada bildirildiyse iletişim kurulur.
| Yöntem | Ne zaman | Yön |
|---|---|---|
| Uygulama olayları (pub/sub) | "Bir şey oldu" bildirimi (fatura kesildi, gönderi oluşturuldu) | Yayıncı → aboneler (webhook) |
| Paylaşılan metafield'lar | Kaynağa bağlı kalıcı veri (fatura numarası, takip numarası) | Yazan → okuyan (API) |
| Keşif kataloğu | Mağazada hangi olayların yayınlandığını öğrenmek | API |
Uygulama Olayları#
Adlandırma#
Yayıncı olay adını kısa haliyle bildirir (invoice.created); Tecof bunu yayıncının slug'ıyla önekler:
app.<yayıncı slug>.<olay adı> ör. app.isbasi.invoice.createdÖneki sunucu ekler; bu sayede bir uygulama başka bir uygulamanın adına olay yayınlayamaz.
Yayınlama#
- Olayı
tecof.app.jsoniçinde bildirin:
{
"appEvents": {
"publishes": [
{ "name": "invoice.created", "description": { "tr": "Fatura oluşturuldu", "en": "Invoice created" } }
]
}
}- Olayı yayınlayın:
await tecof.client(installationId).events.publish("invoice.created", {
orderId: "6720bb00cc11dd22ee33ff44",
orderNumber: "TCF-1001",
invoiceNumber: "ABC2026000000123",
});Ham HTTP: POST /api/v1/app/events { name, data }.
| Kural | Değer |
|---|---|
data boyutu | En fazla 32 KB |
| Bildirilmemiş ad | 400 app-event-undeclared |
| Kapsam | Gerekmez (uygulamanın kendi verisi) |
Abone olma#
Abone uygulama, dinlediği olayları appEvents.subscribes içinde tam adla ya da yayıncı jokeriyle bildirir:
{
"appEvents": {
"subscribes": ["app.isbasi.invoice.created", "app.kargo.*"]
}
}Olay, aynı mağazada kurulu ve bu adı (ya da app.<slug>.* jokerini) listeleyen uygulamalara webhook olarak appUrl + webhooks.path adresine teslim edilir. Abone uygulamada webhooks.path tanımlı değilse uygulama olayları teslim edilemez. Teslimat biçimi, imza, yeniden deneme ve idempotency kuralları normal webhook'larla aynıdır (Webhook'lar); data alanı şu biçimdedir:
{
"id": "evt_91c0d2aa47",
"event": "app.isbasi.invoice.created",
"test": false,
"timestamp": "2026-10-10T09:20:00.000Z",
"merchantId": "66f0c0ffee0000000000abcd",
"installationId": "6720aa00bb11cc22dd33ee77",
"data": {
"source": { "slug": "isbasi", "clientId": "tcfa_yyyyyyyyyyyyyyyy" },
"payload": {
"orderId": "6720bb00cc11dd22ee33ff44",
"orderNumber": "TCF-1001",
"invoiceNumber": "ABC2026000000123"
}
}
}installationId burada abone uygulamanın kurulumudur. Yayıncıyı data.source ile tanırsınız.
Keşif#
Mağazada kurulu uygulamaların yayınladığı olayları listelemek için:
const catalog = await tecof.client(installationId).events.catalog();[
{
"slug": "isbasi",
"appName": "Logo İşbaşı",
"event": "app.isbasi.invoice.created",
"description": { "tr": "Fatura oluşturuldu", "en": "Invoice created" }
}
]Ham HTTP: GET /api/v1/app/events/catalog. Liste, mağazada aktif kurulu platform uygulamalarının appEvents.publishes bildirimlerinden üretilir; event tam (önekli) addır. Panelinizde "şu uygulama kuruluysa şu entegrasyonu aç" gibi akışlar için kullanabilirsiniz.
Paylaşılan Metafield'lar#
visibility: "shared" ile yazılan metafield'ları aynı mağazadaki diğer uygulamalar okuyabilir. Okuyan uygulama, kaynağın okuma kapsamına sahip olmalıdır (sipariş için orders:read).
// Yazan: İşbaşı uygulaması
await api.metafields.set({
ownerType: "order",
ownerId: orderId,
key: "invoiceNumber",
type: "string",
value: "ABC2026000000123",
visibility: "shared",
});
// Okuyan: kargo uygulaması
const shared = await kargoApi.metafields.list({ ownerType: "order", ownerId: orderId, namespace: "isbasi" });
const invoiceNumber = shared.find((m: { key: string }) => m.key === "invoiceNumber")?.value;Namespace yazan uygulamanın slug'ıdır; okurken namespace süzgeciyle hangi uygulamanın verisini istediğinizi belirtin. private metafield'lar başka uygulamalara dönmez.
Örnek: Fatura → Kargo#
Senaryo: İşbaşı uygulaması ödenen sipariş için fatura keser ve invoice.created yayınlar. Mağazada kurulu bir kargo uygulaması (kargo) bu olayı dinler, gönderiyi faturalı olarak oluşturur ve kendi olayı shipment.created'i yayınlar.
sequenceDiagram
participant T as Tecof
participant I as İşbaşı uygulaması (isbasi)
participant K as Kargo uygulaması (kargo)
T->>I: webhook order.paid
I->>I: Faturayı kes
I->>T: PUT /api/v1/metafields (invoiceNumber, shared)
I->>T: POST /api/v1/app/events { name: "invoice.created" }
T->>K: webhook app.isbasi.invoice.created
K->>T: GET /api/v1/orders/:id
K->>K: Gönderiyi oluştur
K->>T: POST /api/v1/app/events { name: "shipment.created" }
T->>I: webhook app.kargo.shipment.createdİşbaşı yapılandırması
{
"slug": "isbasi",
"scopes": ["orders:read", "customers:read", "products:read"],
"webhooks": { "path": "/api/webhooks", "events": ["order.paid"] },
"appEvents": {
"publishes": [{ "name": "invoice.created", "description": { "tr": "Fatura oluşturuldu", "en": "Invoice created" } }],
"subscribes": ["app.kargo.shipment.created"]
}
}Kargo uygulaması yapılandırması
{
"slug": "kargo",
"scopes": ["orders:read"],
"webhooks": { "path": "/api/webhooks", "events": ["order.fulfilled"] },
"appEvents": {
"publishes": [{ "name": "shipment.created", "description": { "tr": "Gönderi oluşturuldu", "en": "Shipment created" } }],
"subscribes": ["app.isbasi.invoice.created"]
}
}Kargo uygulamasının işleyicisi
// kargo: app/api/webhooks/route.ts
import { createWebhookHandler } from "@tecof/app-sdk";
import { tecof } from "@/lib/tecof";
type InvoiceCreated = {
source: { slug: string; clientId: string };
payload: { orderId: string; invoiceNumber: string };
};
export const POST = createWebhookHandler({
app: tecof,
handlers: {
"app.isbasi.invoice.created": async (event) => {
const { payload } = event.data as InvoiceCreated;
const api = tecof.client(event.installationId);
const order = await api.orders.get(payload.orderId);
// … gönderiyi payload.invoiceNumber ile oluştur
await api.events.publish("shipment.created", { orderId: order.id, trackingNumber: "TRK000000001" });
},
},
});Notlar:
- Yayıncı kurulu değilse olay gelmez; abone uygulama bu entegrasyonu isteğe bağlı bir özellik olarak tasarlamalıdır. Keşif kataloğuyla yayıncının varlığını kontrol edebilirsiniz.
- Olay yükü yalnız bildirimdir; kaydın güncel hâlini API'den okuyun.
- Aynı olay birden fazla gelebilir;
X-Tecof-Event-Idile idempotent olun.
Yol Haritası#
Aşağıdakiler gelecek genişletme noktalarıdır ve henüz mevcut değildir:
- Uygulamalar arası doğrudan istek (capability): bir uygulamanın başka bir uygulamanın sunduğu işlevi doğrudan çağırması.
- Vitrin (tema) uzantıları: uygulamaların mağaza vitrinine bileşen eklemesi.