Овој документ засега е само на турски.

Uygulama geliştirme

Başka mağazaların kurabileceği bir uygulama yaz: OAuth ile yetki al, Admin API'yi kullan, panele kendi düğmeni ekle. Akış, anahtar alma, kapsamlar ve aksiyon imzasının doğrulanması.

Nasıl çalışır

  1. Mağazam → Geliştirici → Uygulama geliştir sayfasında uygulamanı oluştur. Herhangi bir Piyodo hesabı oluşturabilir, hesap başına en çok 10 uygulama olur.
  2. client_id, client_secret ve imza anahtarı bir kez gösterilir, sakla. Kaybedersen aynı sayfadan yenilersin. Yenileme eskilerini hemen geçersiz kılar, kurulu mağazaların anahtarına dokunmaz.
  3. Kendi mağazanda dene. Onaysız uygulamayı yalnız geliştiricisi, sahibi olduğu mağazaya kurabilir.
  4. İncelemeye gönder. Sonuç e-postayla gelir. Onaylanınca uygulamalar sayfasında ve mağazaların panelinde listelenir.

Bu sürümde uygulamalar ücretsizdir. Onaylı uygulamanın başka mağazalardaki anahtarı için mağazanın API'li planda olması gerekmez, aboneliğinin geçerli olması yeterlidir. Bir kez onaylanmış uygulama yeniden incelemeye düşse de kurulu mağazalarda çalışmaya devam eder; yeni kurulum onaya kadar kapalıdır. Reddedilen uygulamanın anahtarları 403 döner.

Kendi mağazandaki deneme anahtarı normal plan kuralına tabidir, uygulaman onaylı olsa da. Deneme süresinde tüm özellikler açık olduğu için bu sürede test edebilirsin; süre bitince mağazanın API'li planda olması gerekir. Webhook'lar plandan bağımsız çalışır.

Yetkilendirme

Standart OAuth 2.0 authorization code akışı. Mağaza sahibini ya da yöneticisini onay ekranına yönlendir:

text
https://piyodo.com/oauth/authorize?client_id=pa_...&redirect_uri=https%3A%2F%2Fornek.com%2Fpiyodo%2Fdonus&scope=orders.read%20products.read&state=rastgele-deger
Parametre Zorunlu Açıklama
client_id Evet Uygulamanın kimliği
redirect_uri Evet Kayıtlı dönüş adreslerinden biriyle birebir aynı, https
scope Evet Boşlukla ayrılmış kapsamlar. Uygulamanın beyan ettiklerinin alt kümesi olmalı
state Evet Rastgele değer, olduğu gibi geri döner. Dönüşte kendi kaydınla karşılaştır
response_type Hayır Verilirse code olmalı

Kullanıcı giriş yapar, mağazasını seçer ve kapsamları onaylar. Onay ekranını yalnız mağaza sahibi ve yöneticiler görür, kapalı mağazaya kurulum yapılmaz.

Onaylanırsa dönüş adresine code ve state eklenir:

text
https://ornek.com/piyodo/donus?code=...&state=rastgele-deger

Kod 10 dakika geçerlidir ve tek kullanımlıktır. client_id ya da redirect_uri geçersizse hiçbir yere yönlendirilmez, kullanıcı hata sayfası görür. Uygulama onaylı değilse de geliştiricisi dışında kimse dönüş adresine yönlendirilmez, ret dahil. Bundan sonraki hatalar dönüş adresine error ve state ile gelir:

error Neden
access_denied Kullanıcı vazgeçti
invalid_scope Kapsam boş ya da uygulamanın beyan ettikleri dışında
invalid_request state yok
unsupported_response_type response_type code değil

Kurulum adresi

Mağaza panelde Kur düğmesine bastığında iki yol vardır:

  • Uygulamada kurulum adresi tanımlıysa kullanıcı oraya gider, sen kendi state değerinle yetkilendirmeyi başlatırsın. state doğrulamak istiyorsan bu yolu kullan.
  • Tanımlı değilse doğrudan onay ekranı açılır: tüm beyan edilen kapsamlar, ilk dönüş adresi ve Piyodo'nun ürettiği bir state ile. Bu durumda state senin kaydında olmaz.

Anahtar alma

Kodu sunucu tarafında anahtara çevir. client_secret tarayıcıya hiç gitmemelidir.

POST /api/store/oauth/token

bash
curl -X POST "https://piyodo.com/api/store/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "client_id": "pa_...",
    "client_secret": "pas_...",
    "code": "...",
    "redirect_uri": "https://ornek.com/piyodo/donus"
  }'
json
{
  "access_token": "psk_...",
  "token_type": "Bearer",
  "scope": "orders.read products.read",
  "store": {
    "id": "01J...",
    "name": "Ayşe Butik",
    "slug": "ayse",
    "url": "https://ayse.example.com/"
  }
}

redirect_uri yetkilendirmedekiyle aynı olmalıdır. Hata yanıtları:

Durum error Neden
400 invalid_request Alan eksik
400 unsupported_grant_type grant_type authorization_code değil
401 invalid_client client_id ya da client_secret yanlış
400 invalid_grant Kod yanlış, süresi dolmuş, daha önce kullanılmış ya da adres uyuşmuyor. Mağaza kapalıysa, onay veren kişinin yetkisi kalktıysa ya da uygulama artık kurulamıyorsa da döner

Dakikada en çok 20 istek kabul edilir.

Anahtarı kullanma

access_token normal bir Admin API anahtarıdır. Tüm uçlar, kapsamlar ve hız sınırı Kimlik doğrulama sayfasındaki gibidir, MCP de aynı anahtarla çalışır.

bash
curl "https://piyodo.com/api/store/v1/orders" \
  -H "Authorization: Bearer psk_..."

Her mağaza için ayrı anahtar saklarsın; anahtar mağazayı belirler. Süresi dolmaz, yenileme anahtarı (refresh token) yoktur.

Durum Sonuç
Mağaza uygulamayı kaldırdı Anahtar iptal, 401. Uygulamanın webhook abonelikleri silinir
Yeniden kurulum Yeni kodla yeni anahtar alınır, eski anahtar iptal olur
Mağaza kapandı ya da abonelik bitti 403, abonelik gelince yeniden çalışır
Yönetim uygulamayı yayından kaldırdı 403, webhook gönderilmez. Geliştiricinin kendi mağazası hariç

Kapsamı genişletmek için beyan ettiğin kapsamları güncelle, onaylandıktan sonra mağazayı yetkilendirmeden yeniden geçir.

İnceleme

Onaylı uygulamada site, kurulum adresi, dönüş adresi, kapsam ya da aksiyon değişirse uygulama yeniden incelemeye düşer. Bu sürede kurulu mağazaların anahtarı çalışır, yeni kurulum yapılamaz, aksiyon düğmeleri onaya kadar başka mağazalarda görünmez. Ad ve açıklama değişikliği incelemeye düşürmez.

Panel aksiyonları

Uygulama sipariş, ürün ve müşteri ekranlarına düğme ekleyebilir. En çok 10 aksiyon olur.

json
[
  {
    "id": "kargo-etiketi",
    "label": "Kargo etiketi",
    "target": "order",
    "url": "https://panel.ornek.com/piyodo/etiket"
  }
]
Alan Kural
id Küçük harf, rakam, - ve _. Uygulama içinde benzersiz
label Düğmede görünen ad, en çok 40 karakter
target order, product ya da customer
url https, uygulamanın sitesiyle aynı ana alan adında

Düğmeye basılınca adresin panelde iframe içinde açılır. Çerçeve kısıtlıdır: sandbox="allow-scripts allow-forms allow-same-origin allow-popups" ve referrerpolicy="no-referrer". Sayfan çerçevelenmeye izin vermelidir: X-Frame-Options gönderme, Content-Security-Policy kullanıyorsan frame-ancestors https://piyodo.com ver.

Adrese şu parametreler eklenir:

Parametre Açıklama
store Mağaza kimliği, token yanıtındaki store.id
resource_id Sipariş, ürün ya da müşteri kimliği, API'deki id
action Aksiyonun id değeri
ts Unix zamanı, saniye
sig İmza

Düğmeyi yalnız o kaydı görme yetkisi olan ekip üyesi kullanabilir, kapalı mağazada düğme görünmez.

Aksiyon imzasını doğrulama

Parametreler adres çubuğundan gelir, herkes değiştirebilir. Sayfanı göstermeden önce imzayı doğrula:

text
sig = HMAC-SHA256(imza anahtarı, store + "\n" + resource_id + "\n" + action + "\n" + ts)

Sonuç küçük harf hex'tir. Bayat bağlantı kabul etme: ts en çok 5 dakika eski olsun.

php
function piyodoActionIsValid(array $query, string $signingSecret): bool
{
    foreach (['store', 'resource_id', 'action', 'ts', 'sig'] as $key) {
        if (! is_string($query[$key] ?? null)) {
            return false;
        }
    }
    if (abs(time() - (int) $query['ts']) > 300) {
        return false;
    }
    $text = implode("\n", [$query['store'], $query['resource_id'], $query['action'], $query['ts']]);

    return hash_equals(hash_hmac('sha256', $text, $signingSecret), $query['sig']);
}
javascript
import { createHmac, timingSafeEqual } from 'node:crypto';

export function piyodoActionIsValid(query, signingSecret) {
    const { store, resource_id, action, ts, sig } = query;
    if (![store, resource_id, action, ts, sig].every((v) => typeof v === 'string')) return false;
    if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
    const expected = createHmac('sha256', signingSecret).update([store, resource_id, action, ts].join('\n')).digest('hex');
    return sig.length === expected.length && timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

İmza yalnız isteğin Piyodo panelinden geldiğini kanıtlar; kullanıcının kim olduğunu söylemez. Veriyi store için sakladığın anahtarla, sunucundan Admin API'ye sorarak al.