Webhook Kullanım Rehberi
Webhook'lar, firmanızda bir kayıt oluşturulduğunda, güncellendiğinde veya silindiğinde Paraşüt'ün belirlediğiniz adrese POST isteği göndermesini sağlar. Bu rehber uç noktanızı hazırlamaktan client_key üretmeye, webhook oluşturmaktan gelen isteği doğrulamaya ve verilerinizi API ile eşitlemeye kadar tüm adımları anlatır. Webhook uçları aynı access_token ile çağrılır; eğer henüz yoksa OAuth rehberine bakın.
https://api.parasut.com/v4). Her alanın tam şeması API dokümantasyonunun WEBHOOK ve WEBHOOK İSTEKLERİ bölümlerindedir.Başlamadan Önce
title değeri API client's package does not include webhooks olur. Geliştirici Portalı'ndaki bir API istemcisine ait olmayan bir access token ile yapılan istekler de 403 (Webhooks are only available to Developer Portal API clients) döner.Mutlaka Bilmeniz Gerekenler
- Gövdedeki
data.typetekilwebhookolmalıdır;webhooksgönderirseniz 422 alırsınız (3. adım). uriinternetten erişilebilen bir HTTPS adresi olmalıdır:httpadresler kabul edilmez; özel ağ,localhostve link-local adresler reddedilebilir; yönlendirmeler takip edilmez (1. adım).client_keytam 64 karakterlik[A-Za-z0-9]bir değerdir ve API yanıtlarında hiçbir zaman dönmez; kendi tarafınızda güvenle saklayın (2. adım).- Her istekteki
X-Client-Keyheader'ını sakladığınızclient_keyile sabit zamanlı karşılaştırın, eşleşmeyen istekleri reddedin (4. adım). - Bağlantı 10 saniyede kurulmalı, yanıt 30 saniyede dönmelidir: isteği alır almaz
2xxdönün, uzun işleri arka planda yapın (5. adım). - Aynı event birden fazla kez gelebilir; tekrarları
event_idile ayıklayın veevent_iddeğerini yalnızca eşitlik için karşılaştırın (6. adım). - Sıra garanti edilmez: aynı kaydın isteklerini
data.updated_atile karşılaştırın,deletesonrasında gelenleri işlemeyin,event_dateile sıralamayın (6. adım). - Teslimat garanti edilmez: webhook isteklerini değişiklik bildirimi olarak kullanın ve verileri düzenli aralıklarla API'den eşitleyin (7. adım).
- Tanımadığınız alanları, enum değerlerini ve header'ları yok sayın; gövdeye katı bir şema doğrulaması uygulamayın (4. adım).
- Bazı event'ler her kayıt için gönderilmez:
sales_invoiceupdate,purchase_billvestock_movementistisnalarını Desteklenen Event'ler bölümünde okuyun.
Akışa Genel Bakış
1–3 kurulumdur ve bir kez yapılır; 4–6 gelen her istekte uygulanır; 7–8 sürekli bakım içindir.
Adım Adım Akış
HTTPS Uç Noktanızı Hazırlayın
Abone olduğunuz event gerçekleştiğinde webhook'un uri adresine Content-Type: application/json ile bir POST isteği gönderilir: bu isteği karşılayacak, internetten erişilebilen bir HTTPS uç noktası hazırlayın. Uç nokta aynı adreste yanıt vermeli; başka bir adrese yönlendirmemelidir.
# Uç noktanız yönlendirme (3xx) dönmemeli; Paraşüt yönlendirmeleri takip etmez.
curl -sS -o /dev/null -w "%{http_code}\n" -X POST https://website.com/webhooks \
-H "Content-Type: application/json" \
-d '{}'
# Beklenen: 3xx dışında bir kod (X-Client-Key olmadığı için ör. 401)uri HTTPS olmalıdır; http adresler kabul edilmez. uri internetten erişilebilen bir adres olmalıdır: özel ağ, yerel (localhost) ya da bağlantı-yerel (link-local) adreslere işaret eden bir uri oluşturma ve güncellemede 422 ile reddedilebilir ve bu adreslere webhook isteği gönderilmeyebilir.4xx ve 3xx durumları: teslim edilemedi ve yeniden denenmez; yönlendirmeler takip edilmez. Örneğin https://website.com/webhooks adresinden https://www.website.com/webhooks adresine ya da sondaki / için yapılan bir yönlendirme, event'in teslim edilmemesine yol açar.client_key Üretin
Her webhook isteği bu değeri X-Client-Key header'ında taşır; isteğin Paraşüt'ten geldiğini bu değerle doğrularsınız (4. adım). Örneğin openssl rand -hex 32 komutuyla üretebilirsiniz.
openssl rand -hex 32
# Örnek çıktı (64 karakter):
# 3f9a1c27b84e4d6a9e0f5b2c7d18a4e6f0b3c9d2e5a7184b6c0d2f4e8a1b3c5d
# Node.js ile:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"client_key belirlersiniz: A-Z, a-z ve 0-9 karakterlerinden oluşan, tam 64 karakterlik gizli bir değer. -, _, +, / ya da = gibi karakterler içeren değerler (ör. UUID) bu biçime uymaz ve 422 döner.client_key API yanıtlarında hiçbir zaman dönmez; değeri kendi tarafınızda güvenli biçimde saklayın. client_key silinemez, yalnızca değiştirilebilir. Değeri kaybederseniz ya da sızdığından şüphelenirseniz webhook'u 8. adımdaki gibi yeni bir client_key ile güncelleyin.Webhook Oluşturun
Dinlemek istediğiniz model + action ikilisi için POST /{company_id}/webhooks isteği gönderin. Başarılı istek 201 ile oluşturulan webhook'u döner. Desteklenen ikililer için Desteklenen Event'ler bölümüne bakın.
curl -X POST https://api.parasut.com/v4/{company_id}/webhooks \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-d '{
"data": {
"type": "webhook",
"attributes": {
"model": "contact",
"action": "update",
"uri": "https://website.com/webhooks",
"client_key": "3f9a1c27b84e4d6a9e0f5b2c7d18a4e6f0b3c9d2e5a7184b6c0d2f4e8a1b3c5d"
}
}
}'| Alan | Tip / Örnek | Açıklama |
|---|---|---|
| data.type | enum (zorunlu) | Tekil webhook |
| attributes.model | enum (zorunlu) | Event'leri dinlenecek kaynak: shipment_document, stock_movement, product, contact, sales_invoice, stock_update, company, purchase_bill, inbound_e_invoice |
| attributes.action | enum (zorunlu) | Dinlenecek işlem: create | update | delete |
| attributes.uri | string (zorunlu) | Event'lerin gönderileceği adres; HTTPS olmalıdır (^https://), en fazla 2048 karakter |
| attributes.client_key | string (zorunlu) | Tam 64 karakter [A-Za-z0-9]; webhook isteklerinde X-Client-Key header'ı olarak gönderilir, yanıtlarda dönmez |
Örnekteki client_key yalnızca biçimi gösterir; 2. adımda kendi ürettiğiniz değeri gönderin.
{
"data": {
"id": "42",
"type": "webhook",
"attributes": {
"model": "contact",
"action": "update",
"uri": "https://website.com/webhooks",
"company_id": 123,
"created_at": "2025-01-10T10:00:00.000Z",
"updated_at": "2025-01-10T10:00:00.000Z"
}
}
}data.type: İstek gövdesindeki data.type tekil webhook olmalıdır, webhooks değil.client_id) aittir: aynı firmada her istemci yalnızca kendi webhook'larını görür ve yönetir. Bir istemci, bir firma için her model + action ikilisinden yalnızca bir webhook tanımlayabilir. model ve action webhook oluşturulduktan sonra değiştirilemez.model + action için ikinci istek 422 döner).Gelen İsteği Doğrulayın
İsteğin Paraşüt'ten geldiğini doğrulamak için header'daki değeri sakladığınız client_key ile karşılaştırın. Gövdenin alanları Webhook İsteğinin Gövdesi bölümünde açıklanır.
POST /webhooks HTTP/1.1
Host: website.com
Content-Type: application/json
X-Client-Key: <client_key>
{
"event_id": "9f2c4e7a1b3d5f60718293a4b5c6d7e8",
"company_id": 123,
"resource": "contact",
"action": "update",
"event_date": "2025-01-10T10:55:00Z",
"data": {
"id": 456,
"company_id": 123,
"created_at": "2025-01-09T08:00:00.000Z",
"updated_at": "2025-01-10T10:54:59.123Z",
"data": { "id": "456", "type": "contacts", "attributes": { "name": "..." } }
}
}const crypto = require('crypto');
const express = require('express');
const app = express();
// Webhook'u oluştururken gönderdiğiniz client_key; güvenli bir yerden okuyun.
const CLIENT_KEY = Buffer.from(process.env.WEBHOOK_CLIENT_KEY || '');
function hasValidClientKey(req) {
const received = Buffer.from(req.get('X-Client-Key') || '');
// timingSafeEqual farklı uzunluklarda hata fırlatır; önce uzunlukları karşılaştırın.
if (CLIENT_KEY.length !== 64 || received.length !== CLIENT_KEY.length) return false;
return crypto.timingSafeEqual(received, CLIENT_KEY);
}
// jobs: kendi kalıcı kuyruğunuz (ör. bir veritabanı tablosu ya da mesaj kuyruğu)
// Varsayılan 100kb sınırı büyük gövdelerde 413 döner; 413 yeniden denenmez.
app.post('/webhooks', express.json({ limit: '5mb' }), async (req, res) => {
if (!hasValidClientKey(req)) {
return res.sendStatus(401); // Önerimizdir; durum kodu belirtilmemiştir.
}
await jobs.enqueue(req.body); // Kısa sürmeli: event'i yalnızca kuyruğa yazın.
res.sendStatus(200); // Hemen 2xx dönün (5. adım).
});Rack::Utils.secure_compare, Node.js'te crypto.timingSafeEqual) ve eşleşmeyen istekleri reddedin.408 ve 429 dışındaki 4xx yanıtlar yeniden denenmez: reddettiğiniz istek bu event için tekrar gönderilmez.model, action ya da başka bir enum değeri gelirse hata vermeyin, yok sayın; tanımadığınız alanları ve header'ları da yok sayın.Hemen 2xx Dönün
İsteği doğruladıktan sonra event'i kalıcı bir kuyruğa yazın ve yanıtı bekletmeden 2xx dönün. Event'i işleme, API'den veri okuma gibi uzun işleri kuyruktan ayrı bir süreçte yapın.
// Kuyruktaki event'leri HTTP isteğinden bağımsız, ayrı bir süreçte işleyin.
jobs.process(async (event) => {
await handleEvent(event); // Tekrar ve sıra kontrolü: 6. adım
});2xx döndüğünde istek teslim edilmiş sayılır. Bağlantı 10 saniyede kurulamazsa ya da yanıt 30 saniyede gelmezse istek başarısız sayılır. Uzun süren işleri isteği aldıktan sonra arka planda yapın ve hemen 2xx dönün.Teslimat ve yeniden deneme
| Durum | Ne olur |
|---|---|
2xx | Teslim edildi |
5xx, 408, 429, zaman aşımı, bağlantı ya da SSL hatası | Artan aralıklarla 10 kereye kadar, yaklaşık 4–5 saat boyunca yeniden denenir; sonra bu event için istek gönderilmez |
Diğer 4xx, 3xx | Yeniden denenmez; yönlendirmeler takip edilmez |
Tekrarları ve Sırayı Yönetin
Kuyruktan aldığınız her event'i işlemeden önce daha önce işlenip işlenmediğini ve aynı kayıt için daha yeni bir veri olup olmadığını kontrol edin.
async function handleEvent(event) {
// event_id webhook başınadır; firma + model + action ile birlikte saklayın.
const eventKey = [event.company_id, event.resource, event.action, event.event_id].join(':');
// 1) Tekrar: aynı event_id daha önce işlendiyse atlayın.
if (await db.processedEvents.has(eventKey)) return;
// 2) Sıra: aynı kaydı resource + data.id ile bulun.
const key = event.resource + ':' + event.data.id;
const record = await db.records.get(key);
if (record && record.deleted) {
// Silinmiş kayıt için sonradan gelen create/update işlenmez.
} else if (event.action === 'delete') {
await db.records.set(key, { deleted: true });
} else if (!record || Date.parse(event.data.updated_at) >= Date.parse(record.updated_at)) {
// updated_at değeri daha eski olan isteği uygulamayın.
await db.records.set(key, { updated_at: event.data.updated_at, data: event.data });
}
await db.processedEvents.add(eventKey);
}event_id ile ayıklayın. event_id: Event'in bu webhook için kimliği; aynı event'in tekrar gönderimlerinde değişmez. Tekrar gelen istekleri ayıklamak için kullanın; biçimine güvenmeyin, yalnızca eşitlik için karşılaştırın.Sıralama garantisi yoktur
update isteği create isteğinden önce gelebilir. event_date sıralama için uygun değildir.- Aynı kayda (
resource+data.id) ait istekleridata.updated_atdeğerine göre karşılaştırın;updated_atdeğeri daha eski olan bir isteği daha yenisinin üzerine işlemeyin. - Bir kayıt için
deleteisteği aldıktan sonra aynı kayda ait gelencreateveupdateisteklerini işlemeyin. Kaydın son güncellemesine ait istek, silme isteğinden sonra ulaşabilir; silinmiş bir kaydı bu istekle yeniden oluşturmayın. - Kaydın güncel hâline ihtiyacınız olduğunda onu API'den okuyun.
Verileri API ile Eşitleyin
Webhook isteğini bir değişiklik bildirimi olarak kullanın: kaydın güncel hâlini gerektiğinde API'den okuyun ve verilerinizi düzenli aralıklarla API'den eşitleyin. Endpoint'iniz yeniden deneme süresinden uzun süre erişilemez kalırsa o event'ler için istek gönderilmez; bu boşluğu da eşitleme kapatır.
curl -X GET https://api.parasut.com/v4/{company_id}/contacts/{id} \
-H "Authorization: Bearer ACCESS_TOKEN"Teslimat garantisi yoktur
create isteği hiç gelmeden update ya da delete isteği gelebilir. Kayıtların eksiksiz bir kopyasını tutmanız gerekiyorsa webhook isteklerini bir değişiklik bildirimi olarak kullanın ve verileri düzenli aralıklarla API'den eşitleyin.Webhook'larınızı Yönetin
Webhook'larınızı listeleyin, görüntüleyin, uri veya client_key değerini güncelleyin ve artık ihtiyacınız olmayanları silin. Listelemek ve görüntülemek için Ayarlar okuma, diğer işlemler için Ayarlar tam yetkisi gerekir.
Listeleme
curl -X GET https://api.parasut.com/v4/{company_id}/webhooks \
-H "Authorization: Bearer ACCESS_TOKEN"model + action ikilileriyle sınırlıdır. client_key yanıtta dönmez.Görüntüleme
curl -X GET https://api.parasut.com/v4/{company_id}/webhooks/{id} \
-H "Authorization: Bearer ACCESS_TOKEN"Güncelleme ve client_key değiştirme
curl -X PATCH https://api.parasut.com/v4/{company_id}/webhooks/{id} \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/vnd.api+json" \
-d '{
"data": {
"type": "webhook",
"attributes": {
"client_key": "72dd4f0ed26ed1e46303a06fb37b856e4df9276490fe18ac97ad3268229c9e38"
}
}
}'Webhook'un uri veya client_key değerini günceller; yalnızca gönderdiğiniz alanlar değişir. Başarılı istek 200 ile güncellenen webhook'u döner.
model ve action değişmez: model ve action webhook oluşturulduktan sonra değiştirilemez. Başka bir event'i dinlemek için yeni bir webhook oluşturun, artık ihtiyacınız olmayanı silin. İstekte model ve action göndermeyin; webhook'un mevcut değerinden farklı bir değer 422 döner.client_key değiştirme: client_key gönderilmezse mevcut değer korunur; yeni bir değer gönderildiğinde sonraki webhook istekleri bu değerle yapılır. client_key boş ya da null gönderilerek silinemez. uri değiştiriliyorsa HTTPS olmalıdır.client_key değiştirirken doğrulamanızın kısa bir süre hem eski hem yeni değeri kabul etmesini sağlayın; böylece geçiş sırasında gelen istekleri reddetmezsiniz.Silme
curl -X DELETE https://api.parasut.com/v4/{company_id}/webhooks/{id} \
-H "Authorization: Bearer ACCESS_TOKEN"
# Başarılı yanıt: 204 No Content (gövde yok)Webhook'u siler; bu webhook için artık istek gönderilmez. Başarılı istek 204 ve boş gövde döner.
Desteklenen Event'ler
Her webhook tek bir model + action ikilisini dinler. data.data kaydın JSON:API gösterimidir, data.included kayıtla birlikte gönderilen ilişkili kaynaklardır. Her modelin gövde şeması API dokümantasyonunun WEBHOOK İSTEKLERİ bölümündedir.
model | create | update | delete | data.data | data.included |
|---|---|---|---|---|---|
shipment_document (İrsaliye) | ✓ | ✓ | ✓ | shipment_documents | stock_movements |
stock_movement (Stok hareketi) | ✓ | ✓ | ✓ | stock_movements | product |
product (Ürün) | ✓ | ✓ | ✓ | products | Yok |
contact (Müşteri / Tedarikçi) | ✓ | ✓ | ✓ | contacts | contact_people (delete event'inde yer almaz) |
sales_invoice (Satış faturası) | ✓ | ✓ | – | sales_invoices | details, details.product, contact, active_e_document, failed_e_invoice |
stock_update (Stok güncelleme) | ✓ | – | – | stock_updates | details, details.product, details.warehouse |
company (Firma) | – | ✓ | – | – | Yok; data düz gövdedir |
purchase_bill (Fiş / Fatura) | ✓ | ✓ | – | purchase_bills | details, details.product, supplier |
inbound_e_invoice (Gelen e-Fatura) | ✓ | – | – | e_invoices | Yok |
model ve action değerleri eklenebilir.Her kayıt için gönderilmeyen event'ler
Bazı event'ler her kayıt için gönderilmez:
sales_invoice update: yalnızca e-Fatura ya da e-Arşiv belgesi olan (relationships.active_e_document tipi e_invoices ya da e_archives) faturalar için gönderilir; e-SMM'si olan faturalar için gönderilmez. Teklifler ve tekrarlayan fatura şablonları (item_type: estimate, recurring_invoice, recurring_estimate, recurring_export) için gönderilmez. create bu türler için de gönderilir; gerekiyorsa item_type ile ayıklayın.purchase_bill create ve update: gelen bir e-Faturaya bağlı (relationships.active_e_document dolu) fiş/faturalar ve tekrarlayan fiş/fatura şablonları (item_type: recurring_purchase_bill) için gönderilmez. Gelen e-Faturaları inbound_e_invoice event'iyle izleyin.stock_movement: stok güncellemesinden ve depo transferinden doğan stok hareketleri için create, update ve delete gönderilmez. Stok güncellemelerini stock_update event'iyle izleyin; depo transferleri için webhook yoktur.Silme event'leri
delete event'inin verisi: delete event'inde data, kaydın silinmeden hemen önceki hâlidir ve diğer event'lerle aynı yapıdadır; kayıtla birlikte silinen ilişkili kayıtlar data.included içinde yer almayabilir.Tabloda delete için – işaretli modellerde silme event'i gönderilmez; bu kayıtların silindiğini verileri API'den eşitleyerek fark edin (7. adım).
Satış faturası PDF'i (pdf_url)
sales_invoice update event'inin verisine pdf_url alanı eklenir. Bu bağlantı 2 saat geçerlidir. Alan data.data.attributes.pdf_url konumundadır.company event'i
data JSON:API biçiminde değildir; firmanın alanlarını düz olarak içerir.company event'inde ise data firmanın şu alanlarını düz olarak içerir: id, name, legal_name, tax_number, tax_office, mersis_no, city, district, occupation_field, category, owner_email, contact_person, contact_phone_number, e_invoice_vkn, e_invoicing_enabled, e_invoice_inbox, e_invoice_outbox, e_invoice_trade_registry, trial_status, trial_end_date, new_subscription_status, subscription_renewal_date, accessible_until, tmp_access_end_date, subscription_tmp_access_end_date, credit_balance, credit_service_balance, logo_url, created_at, updated_at.
Webhook İsteğinin Gövdesi
Gövdenin zarfı (event_id, company_id, resource, action, event_date, data) hepsinde aynıdır; data modele göre değişir.
Zarf alanları
| Alan | Tip / Örnek | Açıklama |
|---|---|---|
| event_id | string | Event'in bu webhook için kimliği; aynı event'in tekrar gönderimlerinde değişmez. Tekrar gelen istekleri ayıklamak için kullanın; biçimine güvenmeyin, yalnızca eşitlik için karşılaştırın |
| company_id | integer | Firma ID |
| resource | enum | Webhook'un model değeri |
| action | enum | create, update veya delete |
| event_date | date-time | Paraşüt'ün event'i işlediği zaman (ISO 8601, UTC). Kaydın değiştiği an değildir; sıralama için kullanmayın |
| data | object | Kaydın verisi (nesne) |
data alanları
data, kaydın API v4'teki JSON:API gösterimini (data.data, varsa data.included) ve en üst seviyede id, company_id, created_at, updated_at alanlarını içerir. company event'i bu yapıda değildir (Desteklenen Event'ler bölümüne bakın).
| Alan | Tip / Örnek | Açıklama |
|---|---|---|
| data.id | integer | Kayıt ID; data.data.id ile aynı kaydı gösterir |
| data.company_id | integer | Firma ID |
| data.created_at | date-time | Kaydın oluşturulduğu zaman |
| data.updated_at | date-time | Kaydın son değiştiği zaman; event'leri sıralamak için bunu kullanın |
| data.data | object | Kaydın JSON:API kaynak nesnesi (id, type, attributes, relationships) |
| data.included | array | Kayıtla birlikte gönderilen ilişkili kaynaklar; modele göre değişir |
data.id sayıdır (456), JSON:API nesnesindeki data.data.id ise metindir ("456").data'ya zamanla yeni alanlar, enum alanlarına yeni değerler eklenebilir. Bilinmeyen alanları ve değerleri yok sayın ve gövdeye katı bir şema doğrulaması uygulamayın; garanti edilen alanlar yukarıda listelenenlerdir.Hata Yanıtları
Hata yanıtları JSON:API biçimindedir (Content-Type: application/vnd.api+json). Gövde, bir veya daha fazla hata nesnesi içeren bir errors dizisidir: title hatanın kısa açıklaması, detail alan adıyla birlikte tam açıklamasıdır; doğrulama hatalarında source.pointer hatalı alanı gösterir.
{
"errors": [
{
"title": "must be https",
"detail": "Uri must be https",
"source": { "pointer": "/data/attributes/uri" }
}
]
}| Durum | Ne zaman döner |
|---|---|
| 400 | İstek gövdesinde data yok ya da data / data.attributes bir nesne değil; gövde geçerli bir JSON değil |
| 401 | Access token geçersiz ya da süresi dolmuş veya kullanıcının bu company_id için erişimi yok |
| 402 | Firmanın Paraşüt kullanım süresi sona ermiş |
| 403 | API paketiniz webhook içermiyor, access token Geliştirici Portalı'ndaki bir API istemcisine ait değil, kullanıcının bu firmada gerekli Ayarlar yetkisi ya da üçüncü taraf entegrasyon yetkisi yok veya API istemcinizin bu firmaya erişimi yok |
| 404 | Webhook (id) bulunamadı ya da başka bir API istemcisine ait |
| 422 | Doğrulama hatası: data.type webhook değil; client_key biçimi geçersiz; uri geçersiz, HTTPS değil ya da kabul edilmeyen bir adres; model veya action geçersiz ya da bu model + action ikilisi desteklenmiyor; aynı model + action için zaten bir webhook var; mevcut bir webhook'un model veya action değeri değiştirilmek istendi |
| 500, 503 | Paraşüt tarafında geçici bir sorun; isteği daha sonra yeniden deneyin |
- 402 yanıtında
errorsdizisi hata nesneleri değil, metinler içerir:{"errors": ["Paraşüt kullanım süreniz sona ermiş."]}. - Geçerli bir JSON olmayan istek gövdesi uca ulaşmadan 400 ile reddedilir; yanıt JSON:API değildir (
Content-Type: application/json,{"error": "Invalid JSON"}).
source.pointer değerini kullanın.Doğrulama kuralları istek şemalarında yer alır; isteği göndermeden önce bunları kendi tarafınızda kontrol etmenizi öneririz.
403 yanıtının sebepleri
Hatanın title değeri sebebi belirtir:
title | Sebep |
|---|---|
API client's package does not include webhooks | API paketi webhook içermiyor |
Webhooks are only available to Developer Portal API clients | Access token bir API istemcisine ait değil |
Forbidden | Kullanıcının gerekli Ayarlar yetkisi yok |
User has no 3rd party integration permission for company: 123 | Kullanıcının üçüncü taraf entegrasyon yetkisi yok |
API client has no access to company: 123 | API istemcisinin bu firmaya erişimi yok |