Skip to content

Winglark

Geliştirici başvurusu

Winglark API ve webhook’lar

Etkinlikleri, misafirleri, yanıtları ve girişleri okuyun; misafir ekleyin; bir şey olduğu anda haber alın. JSON ile çalışan bir REST API, yetkileri sınırlı anahtarlar ve imzalı webhook’lar.

API ve webhook’lar Professional ve Agency planlarında vardır. Anahtarları ve webhook’ları çalışma alanının sahibi ya da bir yönetici, Şirket → Entegrasyonlar bölümünden oluşturur.

Genel bakış

Temel adres https://winglark.com/api/v1. Her istek ve yanıt HTTPS üzerinden JSON’dur. Tarihler UTC’de ISO-8601, kimlikler UUID’dir.

API sunucular içindir. CORS başlığı göndermez ve çerezleri yok sayar: tarayıcıdan değil, kendi sunucunuzdan çağırın ve anahtarı istemci kodunun dışında tutun.

Kimlik doğrulama

Anahtarı Authorization başlığında bearer olarak gönderin. Anahtar yalnızca oluşturulduğu anda bir kez gösterilir; Winglark yalnızca anahtarlı bir özetini saklar.

Bir anahtar, onu oluşturan üye adına ve yetkileriyle sınırlı çalışır. İptal edilmişse ya da süresi dolmuşsa, o üye çalışma alanından ayrılmışsa ya da entegrasyonları artık yönetemiyorsa, ya da çalışma alanının planı artık API’yi içermiyorsa reddedilir.

curl https://winglark.com/api/v1/events \
  -H "Authorization: Bearer wlk_live_ab12cd34_…"

Yetkiler

Her uç nokta bir yetki ister. guests:write yetkisi olan bir anahtar misafirleri okuyabilir de. İletişim bilgileri (e-posta, telefon), anahtar bu bilgileri görebilen bir üye tarafından iletişim bilgileri açık olarak oluşturulmadıysa maskelenir.

YetkiAnlamı
events:readEtkinlikleri oku. Başlıklar, tarihler, yerler ve durum.
guests:readMisafirleri oku. Her etkinliğin misafir listesi.
guests:writeMisafir ekle ve düzenle. Paneldeki kurallarla: plan sınırı ve mükerrer kayıt denetimi geçerlidir.
rsvps:readYanıtları oku. Kim yanıt verdi, kaç kişi geliyor. Beslenme, alerji ve erişilebilirlik yanıtları asla.
checkins:readGirişleri oku. Kim, ne zaman ve hangi kapıdan girdi.
webhooks:manageWebhook’ları yönet. Bir otomasyon aracının kendi kendine abone olup aboneliği bırakmasını sağlar.

Hatalar

Hatalar HTTP durum kodunu ve değişmeyen bir code ile insanlar için bir cümle içeren JSON gövdesini kullanır. Her yanıtta X-Request-Id vardır; bize yazarken bunu belirtin.

400
Bir parametre geçerli değil.
401
Anahtar yok, tanınmıyor ya da iptal edilmiş veya süresi dolmuş.
403
Anahtarın yetkisi yok, oluşturan kişi erişimini kaybetti ya da plan API’yi içermiyor.
404
Bu çalışma alanında böyle bir kayıt yok.
409
İstek kayıtla çelişiyor: aynı adres, planın misafir sınırı, kapanmış bir etkinlik.
422
Alanlar eksik ya da geçerli değil.
429
Çok fazla istek; Retry-After süresini bekleyin.
500
Bizden kaynaklı. Aynı Idempotency-Key ile yeniden deneyin.
HTTP/1.1 409 Conflict
X-Request-Id: req_4f1e…

{ "error": { "code": "guest_limit_reached", "message": "This event has reached the guest limit of the workspace plan." } }

Sayfalama

Listeler en yeniden başlar ve en fazla limit kadar öğe döndürür (varsayılan 50, en çok 100). has_more true ise sonraki sayfa için next_cursor değerini cursor olarak gönderin. Misafir ve yanıt listeleri ISO tarih olarak updated_since de kabul eder.

İstek sınırları

Anahtar başına dakikada 600, ağ başına dakikada 1.200 istek. Sınır aşılırsa yanıt, saniye cinsinden Retry-After ile 429 olur. Geçersiz bir anahtarla tekrarlanan istekler on dakika boyunca reddedilir.

Tekrarlanan istekler

Oluşturma isteklerinde Idempotency-Key başlığı gönderin. 24 saat boyunca aynı anahtar ve aynı gövdeyle yapılan bir yeniden deneme, ikinci bir misafir oluşturmak yerine ilk yanıtı (Idempotent-Replayed olarak işaretli) döndürür. Aynı anahtar farklı bir gövdeyle gelirse 422 ile reddedilir.

curl -X POST https://winglark.com/api/v1/events/{event_id}/guests \
  -H "Authorization: Bearer wlk_live_ab12cd34_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: crm-10442-create" \
  -d '{ "first_name": "Ada", "email": "ada@example.com" }'

Uç noktalar

Her liste uç noktası limit ve cursor alır.

GET/v1/me

Anahtarın kendisi: yetkileri ve çalışma alanı. Bir anahtarı denemek için kullanın.

Yetki: —

{
  "object": "api_key",
  "id": "3b2a1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
  "name": "CRM sync",
  "prefix": "wlk_live_ab12cd34",
  "scopes": ["events:read", "guests:read", "rsvps:read"],
  "contacts_visible": false,
  "created_at": "2026-11-04T10:00:00.000Z",
  "expires_at": null,
  "organization": { "id": "9d8c7b6a-5f4e-4d3c-a2b1-0f9e8d7c6b5a", "name": "Northwind Events" }
}

GET/v1/events

Çalışma alanının etkinlikleri, en yeniden başlayarak. status ile süzün.

Yetki: events:read · ?status=active&limit=20

{
  "object": "list",
  "data": [
    {
      "id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "object": "event",
      "title": "Spring partner summit",
      "summary": "",
      "status": "active",
      "type": "corporate",
      "starts_at": "2026-12-03T09:00:00.000Z",
      "ends_at": "2026-12-03T17:00:00.000Z",
      "timezone": "Europe/Berlin",
      "locale": "en",
      "location_mode": "in_person",
      "venue_name": "Hall 4",
      "venue_address": "Messedamm 22, Berlin",
      "rsvp_deadline": "2026-11-26T23:00:00.000Z",
      "created_at": "2026-10-20T08:12:44.120Z",
      "updated_at": "2026-11-02T15:03:10.004Z"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMS0wNFQxMDoyMTowMy41NTFafGI4ZTFkM2M0LTlmMjAtNGE3Yi04YzYxLTVkMmUwZjlhM2IxNw"
}

GET/v1/events/{event_id}

Tek bir etkinlik.

Yetki: events:read

{
  "id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "object": "event",
  "title": "Spring partner summit",
  "summary": "",
  "status": "active",
  "type": "corporate",
  "starts_at": "2026-12-03T09:00:00.000Z",
  "ends_at": "2026-12-03T17:00:00.000Z",
  "timezone": "Europe/Berlin",
  "locale": "en",
  "location_mode": "in_person",
  "venue_name": "Hall 4",
  "venue_address": "Messedamm 22, Berlin",
  "rsvp_deadline": "2026-11-26T23:00:00.000Z",
  "created_at": "2026-10-20T08:12:44.120Z",
  "updated_at": "2026-11-02T15:03:10.004Z"
}

GET/v1/events/{event_id}/guests

Bir etkinliğin misafirleri. include_archived=true listeden çıkarılan misafirleri de ekler.

Yetki: guests:read · ?updated_since=2026-11-01T00:00:00Z

{
  "object": "list",
  "data": [
    {
      "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
      "object": "guest",
      "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "first_name": "Ada",
      "last_name": "Kaya",
      "display_name": "Ada Kaya",
      "email": "a•••@example.com",
      "phone": "••• ••• 321",
      "company": "Northwind",
      "job_title": "Head of Partnerships",
      "locale": "en",
      "guest_type": "standard",
      "status": "pending",
      "source": "api",
      "tags": ["partner"],
      "external_reference": "crm-10442",
      "expected_party_size": 1,
      "archived_at": null,
      "created_at": "2026-11-04T10:21:03.551Z",
      "updated_at": "2026-11-04T10:21:03.551Z"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMS0wNFQxMDoyMTowMy41NTFafGI4ZTFkM2M0LTlmMjAtNGE3Yi04YzYxLTVkMmUwZjlhM2IxNw"
}

GET/v1/events/{event_id}/guests/{guest_id}

Tek bir misafir.

Yetki: guests:read

{
  "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
  "object": "guest",
  "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "first_name": "Ada",
  "last_name": "Kaya",
  "display_name": "Ada Kaya",
  "email": "a•••@example.com",
  "phone": "••• ••• 321",
  "company": "Northwind",
  "job_title": "Head of Partnerships",
  "locale": "en",
  "guest_type": "standard",
  "status": "pending",
  "source": "api",
  "tags": ["partner"],
  "external_reference": "crm-10442",
  "expected_party_size": 1,
  "archived_at": null,
  "created_at": "2026-11-04T10:21:03.551Z",
  "updated_at": "2026-11-04T10:21:03.551Z"
}

POST/v1/events/{event_id}/guests

Misafir ekleyin. Yalnızca first_name zorunlu. Plan sınırları ve aynı adres kuralı geçerlidir.

Yetki: guests:write

{
  "first_name": "Ada",
  "last_name": "Kaya",
  "email": "ada@example.com",
  "company": "Northwind",
  "tags": ["partner"],
  "external_reference": "crm-10442"
}
{
  "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
  "object": "guest",
  "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "first_name": "Ada",
  "last_name": "Kaya",
  "display_name": "Ada Kaya",
  "email": "a•••@example.com",
  "phone": "••• ••• 321",
  "company": "Northwind",
  "job_title": "Head of Partnerships",
  "locale": "en",
  "guest_type": "standard",
  "status": "pending",
  "source": "api",
  "tags": ["partner"],
  "external_reference": "crm-10442",
  "expected_party_size": 1,
  "archived_at": null,
  "created_at": "2026-11-04T10:21:03.551Z",
  "updated_at": "2026-11-04T10:21:03.551Z"
}

PATCH/v1/events/{event_id}/guests/{guest_id}

Bir misafirin adını, iletişim bilgilerini, şirketini, unvanını, dilini, türünü ya da etiketlerini değiştirin.

Yetki: guests:write

{ "job_title": "Chief Partnerships Officer", "tags": ["partner", "vip-desk"] }
{
  "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
  "object": "guest",
  "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "first_name": "Ada",
  "last_name": "Kaya",
  "display_name": "Ada Kaya",
  "email": "a•••@example.com",
  "phone": "••• ••• 321",
  "company": "Northwind",
  "job_title": "Head of Partnerships",
  "locale": "en",
  "guest_type": "standard",
  "status": "pending",
  "source": "api",
  "tags": ["partner"],
  "external_reference": "crm-10442",
  "expected_party_size": 1,
  "archived_at": null,
  "created_at": "2026-11-04T10:21:03.551Z",
  "updated_at": "2026-11-04T10:21:03.551Z"
}

GET/v1/events/{event_id}/rsvps

Bir etkinliğin yanıtları, en son değişenden başlayarak. response ile süzün.

Yetki: rsvps:read · ?response=yes

{
  "object": "list",
  "data": [
    {
      "id": "0c9b7a5e-3d1f-4e2a-b6c8-9f0e1d2c3b4a",
      "object": "rsvp",
      "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "guest_id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
      "response": "yes",
      "party_size": 2,
      "attendance_mode": "in_person",
      "revision": 1,
      "responded_via": "link",
      "responded_at": "2026-11-05T18:40:12.000Z",
      "updated_at": "2026-11-05T18:40:12.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMS0wNFQxMDoyMTowMy41NTFafGI4ZTFkM2M0LTlmMjAtNGE3Yi04YzYxLTVkMmUwZjlhM2IxNw"
}

GET/v1/events/{event_id}/checkins

Bir etkinliğin kapı kayıtları, en yeniden başlayarak.

Yetki: checkins:read

{
  "object": "list",
  "data": [
    {
      "id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
      "object": "checkin",
      "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "guest_id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
      "action": "admitted",
      "result": "ok",
      "admitted": 2,
      "occurred_at": "2026-12-03T08:57:31.000Z",
      "recorded_offline": false
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMS0wNFQxMDoyMTowMy41NTFafGI4ZTFkM2M0LTlmMjAtNGE3Yi04YzYxLTVkMmUwZjlhM2IxNw"
}

GET/v1/webhooks

Çalışma alanının webhook uç noktaları.

Yetki: webhooks:manage

{ "object": "list", "data": [{
    "id": "e2d4c6b8-a0f1-4e3d-9c5b-7a8f6e4d2c1b",
    "object": "webhook_endpoint",
    "url": "https://hooks.example.com/winglark",
    "description": "CRM sync",
    "events": ["rsvp.submitted", "checkin.admitted"],
    "event_ids": [],
    "include_contacts": false,
    "active": true,
    "disabled_reason": null,
    "source": "api",
    "created_at": "2026-11-04T10:30:00.000Z"
  }], "has_more": false, "next_cursor": null }

POST/v1/webhooks

Bir adresi abone edin. Yanıt, imza anahtarını bir kez içerir.

Yetki: webhooks:manage

{
  "url": "https://hooks.example.com/winglark",
  "events": ["rsvp.submitted", "checkin.admitted"],
  "event_ids": [],
  "description": "CRM sync"
}
{
  "id": "e2d4c6b8-a0f1-4e3d-9c5b-7a8f6e4d2c1b",
  "object": "webhook_endpoint",
  "url": "https://hooks.example.com/winglark",
  "description": "CRM sync",
  "events": ["rsvp.submitted", "checkin.admitted"],
  "event_ids": [],
  "include_contacts": false,
  "active": true,
  "disabled_reason": null,
  "source": "api",
  "created_at": "2026-11-04T10:30:00.000Z",
  "secret": "whsec_6Jx…shown once…"
}

DELETE/v1/webhooks/{webhook_id}

Aboneliği bırakın.

Yetki: webhooks:manage

204 No Content

Webhook’lar

Panelden ya da POST /v1/webhooks ile bir uç nokta ekleyin, olay türlerini seçin ve isterseniz bazı etkinliklerle sınırlayın. Winglark her olay için bir JSON mesajı gönderir.

10 saniye içinde herhangi bir 2xx ile yanıt verin. Yönlendirmeler izlenmez. Mesajdaki id her yeniden denemede ve her uç nokta için aynıdır: daha önce işlediğiniz bir mesajı yok saymak için kullanın.

Olay türüNe zaman
guest.createdBir misafir eklendi: elle, içe aktarmayla, API ile ya da kapıda.
guest.updatedBir misafirin bilgileri değişti.
guest.archivedBir misafir listeden çıkarıldı.
rsvp.submittedBir misafir yanıt verdi ya da yanıtını değiştirdi.
invitation.sentBir davet e-postası e-posta sağlayıcısına teslim edildi.
invitation.deliveredAlıcının e-posta sunucusu daveti kabul etti.
invitation.bouncedDavet teslim edilemedi.
checkin.admittedBiri kapıdan ya da bir kiosktan içeri alındı.
ticket.issuedÖdenmiş bir sipariş için biletler oluşturuldu.
event.publishedBir etkinlik yayına girdi: misafirlerin bağlantıları var ve kapı önem kazandı.
event.cancelledBir etkinlik iptal edildi.
seatmap.publishedBir oturma planı misafirlere yayımlandı.
badge.printedYaka kartları basıldı.

Mesaj

Her mesajın zarfı aynıdır. data, ilgili kaydı API’nin döndürdüğü biçimde taşır. Mesajlarda davet bağlantıları, bilet kodları, misafirin özel notu ya da beslenme, alerji ve erişilebilirlik yanıtları asla bulunmaz.

Winglark-Signature
t=1762338012,v1=5f2b…c9e1
Winglark-Event
rsvp.submitted
Winglark-Delivery
7c1e9a42-…
User-Agent
Winglark-Webhooks/1
Content-Type
application/json
{
  "id": "evt_3f9a1c7e5b2d4a6c8e0f1a2b",
  "object": "event",
  "type": "rsvp.submitted",
  "api_version": "v1",
  "created_at": "2026-11-05T18:40:12.481Z",
  "organization_id": "9d8c7b6a-5f4e-4d3c-a2b1-0f9e8d7c6b5a",
  "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "data": {
    "rsvp": {
      "id": "0c9b7a5e-3d1f-4e2a-b6c8-9f0e1d2c3b4a",
      "object": "rsvp",
      "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "guest_id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
      "response": "yes",
      "party_size": 2,
      "attendance_mode": "in_person",
      "revision": 1,
      "responded_via": "link",
      "responded_at": "2026-11-05T18:40:12.000Z",
      "updated_at": "2026-11-05T18:40:12.000Z"
    },
    "guest": { "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17", "first_name": "Ada", "last_name": "Kaya", "email": "a•••@example.com", "…": "…" },
    "response": "yes",
    "party_size": 2,
    "revision": 1,
    "revised": false,
    "via": "link"
  }
}

İmzayı doğrulama

Her mesaj bir Winglark-Signature başlığı taşır: t imzalandığı Unix zamanıdır, v1 ise t, bir nokta ve ham gövdenin, uç noktanızın anahtarıyla hesaplanmış onaltılık HMAC-SHA256 değeridir.

JSON’u ayrıştırmadan önce ham baytlar üzerinden hesaplayın, sabit sürede karşılaştırın ve saatinizden beş dakikadan fazla farklı bir t değerini reddedin. Anahtar yenilendikten sonra 24 saat boyunca iki v1 değeri olur; biri eşleşirse mesajı kabul edin.

Node.js

import { createHmac, timingSafeEqual } from 'node:crypto';
import express from 'express';

const secret = process.env.WINGLARK_WEBHOOK_SECRET; // whsec_…
const app = express();

// The raw body: the signature covers the bytes, not the parsed JSON.
app.post('/winglark', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('Winglark-Signature') ?? '';
  const parts = header.split(',').map((part) => part.split('='));
  const t = Number(parts.find(([key]) => key === 't')?.[1]);
  const signatures = parts.filter(([key]) => key === 'v1').map(([, value]) => value);

  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return res.sendStatus(400);

  const expected = createHmac('sha256', secret).update(`${t}.`).update(req.body).digest();
  const valid = signatures.some((signature) => {
    const given = Buffer.from(signature, 'hex');
    return given.length === expected.length && timingSafeEqual(given, expected);
  });
  if (!valid) return res.sendStatus(400);

  const event = JSON.parse(req.body.toString('utf8'));
  // Deduplicate on event.id: a message can arrive more than once.
  res.sendStatus(204);
});

app.listen(3000);

Python

import hashlib
import hmac
import json
import os
import time

from flask import Flask, abort, request

SECRET = os.environ["WINGLARK_WEBHOOK_SECRET"].encode()  # whsec_…
app = Flask(__name__)


@app.post("/winglark")
def winglark():
    header = request.headers.get("Winglark-Signature", "")
    parts = [part.split("=", 1) for part in header.split(",") if "=" in part]
    t = next((value for key, value in parts if key == "t"), None)
    signatures = [value for key, value in parts if key == "v1"]

    if not t or not t.isdigit() or abs(time.time() - int(t)) > 300:
        abort(400)

    raw = request.get_data()  # the raw bytes, before any JSON parsing
    expected = hmac.new(SECRET, t.encode() + b"." + raw, hashlib.sha256).hexdigest()
    if not any(hmac.compare_digest(expected, signature) for signature in signatures):
        abort(400)

    event = json.loads(raw)
    # Deduplicate on event["id"]: a message can arrive more than once.
    return "", 204

Yeniden denemeler

2xx almayan bir gönderim 1 dakika, 5 dakika, 30 dakika, 2 saat, 6 saat, 12 saat ve 24 saat sonra yeniden denenir, ardından başarısız sayılır. Yeniden denemeler zamanı geldikten sonraki ilk fırsatta, en geç bir saat içinde gönderilir.

Bir uç noktaya yapılan her gönderim üç gün boyunca başarısız olursa Winglark o adrese göndermeyi durdurur ve panelde bunu söyler. Alıcı düzelince sürdürün; başarısız bir gönderim kayıttan yeniden gönderilebilir.

  1. 1. 1 min
  2. 2. 5 min
  3. 3. 30 min
  4. 4. 2 h
  5. 5. 6 h
  6. 6. 12 h
  7. 7. 24 h

Sürümler

Bu, 1. sürüm. Bu sürüm içinde yalnızca ekleme yaparız: yeni alanlar, yeni olay türleri, yeni isteğe bağlı parametreler. Tanımadığınız alanları yok sayın. Bir entegrasyonu bozabilecek her değişiklik, önceden duyurulan yeni bir sürüme gider.

Otomasyon platformları

REST hook destekleyen araçlar webhooks:manage yetkili bir anahtarla POST /v1/webhooks ile abone olabilir, DELETE /v1/webhooks/{id} ile aboneliği bırakabilir. GET /v1/me bir anahtarı dener. En yeniden başlayan liste uç noktaları örnek veri olarak da kullanılabilir.