Connect'ten gelen tek-kullanımlık code'u, sunucu-sunucu bir istekle kalıcı credential'lara çevirirsin: apiKey, webhookSecret, tenantId ve gerçekten verilen scopes. Bu credential'ları tenant başına saklarsın.
POST {RESTOMENUM_BASE}/plugin-api/oauth/token
// {RESTOMENUM_BASE} = ortam tabanı (kanonik liste /docs/api):
// Dev / Sandbox : https://sandbox.plugins.restomenum.app
// Production : https://plugins.restomenum.app
Content-Type: application/json
{
"grant_type": "authorization_code",
"code": "<connect ile gelen tek-kullanımlık code>",
"client_id": "<pluginId — eklenti UUID'si; SLUG DEĞİL (slug → 401 invalid_client)>",
"client_secret": "<portalda üretilen cs_...>"
}{RESTOMENUM_BASE} ortam tabanıdır. Sabitleme — /connect'e gelen environment parametresiyle seç:
environment | Ortam | Base URL |
|---|---|---|
| sandbox | Dev / Sandbox | https://sandbox.plugins.restomenum.app |
| production | Production | https://plugins.restomenum.app |
200 OK
// ZARF (teyitli): BAŞARI yanıtı DAİMA zarflıdır — alanlar `data` İÇİNDEDİR, kökte DEĞİL.
// Kökten okuyan kod alanları undefined görür → canlıda patlar.
// ⚠️ HATA yanıtı bilinçli olarak FARKLIDIR — aşağıdaki TOKEN_ERROR'a bak.
{
"success": true,
"data": {
"tokenType": "...", // token tipi
"environment": "sandbox", // "sandbox" | "production" — KOŞULSUZ gelir; credential'ı tenant + ORTAM başına sakla
"tenantId": "...", // tenant kimliği (kurulumu bununla eşle)
"pluginId": "...", // eklenti (client) id — client_id ile AYNI UUID
"version": "...", // kurulum manifest sürümü
"scopes": ["orders:read", "events:subscribe", "..."], // gerçekten verilen yetkiler
"apiKey": "...", // bu tenant için Callback API çağrılarında kullan
"webhookSecret": "..." // bu tenant'ın webhook + session token imzası
}
}data içindedir, kökte değil. Kökten okuyan parse kodu (body.apiKey) undefined görür ve entegrasyonun canlıda hata verir; doğrusu body.data.apiKey. Resmi SDK exchangeCode bunu zaten çözer.error ve error_description kökte döner, çünkü RFC 6749 §5.2 standart OAuth istemcilerinin beklediği şekil budur. { success:false, message } yanına geri-uyum aynası olarak konur. Sözleşmedeki tek asimetri budur — başarıda zarf, hatada RFC şekli.4xx
{
"error": "invalid_request", // RFC 6749 §5.2 — KÖKTE
"error_description": "...", // RFC 6749 §5.2 — KÖKTE
"success": false, // geri-uyum aynası
"message": "..." // geri-uyum aynası
}apiKey — bu tenant için Callback API çağrılarında kullanılır. Üç parçalıdır: serverId.pluginId.secret. Buradaki serverId, zarftaki (envelope) tenantId ile aynı kimliktir (tenantId = serverId'nin dış adı).webhookSecret — webhook + hook imza doğrulaması ve session token doğrulaması.tenantId — tenant kimliği; kurulumu ve gelen event'leri bununla eşle. (apiKey'in içindeki serverId'nin dış adı — aynı kimlik.)scopes — kurulumda fiilen verilen yetkiler (manifest'te istediğinin alt kümesi olabilir)./connect'te aldığın code + client_id + client_secret ile POST et. client_id = eklentinin pluginId'si (UUID) — eklenti detay sayfasında client_id olarak gösterilir. Slug değildir; slug gönderirsen 401 invalid_client alırsın.tenantId, apiKey, webhookSecret, scopes) tenantId başına güvenli sakla.scopes'a göre özelliklerini koşullu çalıştır (verilmeyen yetkiyi varsayma).apiKey'ini portaldan yenileyebilirsin: eklentinin Teslim logları → Teslim Sağlığı tablosunda kurulum satırındaki "API key yenile" butonu.401 alır. Kurulumu kaldırıp yeniden kurmana gerek yok.apiKey'in başka bir son kullanma süresi yoktur — rotate edilene (veya kurulum kaldırılana) kadar geçerlidir.Token ucu artık standart OAuth 2.0 hatası döndürür — başarı yanıtı değişmedi (Connect akışını bozmaz), yalnız hata şekli standartlaştı:
| HTTP | error | Anlam |
|---|---|---|
| 401 | invalid_client | client_id/client_secret hatalı — en sık sebep: client_id yerine slug göndermek (doğrusu eklenti UUID'si) |
| 400 | invalid_grant | code geçersiz/kullanılmış/süresi dolmuş → yeniden Connect |
| 400 | invalid_request | Eksik/yanlış parametre |
| 400 | unsupported_grant_type | grant_type desteklenmiyor |
| 500 | server_error | Geçici sunucu hatası → tekrar dene |
{ error, error_description } (standart OAuth lib'leri bunu bekler).{ success:false, message } alanları da gönderilir (kademeli geçiş) — ama HTTP status'a göre dallan.code tek kullanımlıktır; exchange invalid_grant ile başarısız olursa kullanıcıyı yeniden Connect'e yönlendir. client_secret yalnız bu sunucu çağrısında kullanılır.