Geliştirici dokümantasyonu · v1

MoonX'i kendi yazılımınıza bağlayın

Cari, ürün, stok ve faturalarınıza güvenle erişin. API REST yapısındadır, JSON konuşur ve her firma yalnızca kendi verisini görür.

Hızlı başlangıç

  1. 1MoonX panelinde Ayarlar → Entegrasyon bilgilerim sayfasından bir anahtar oluşturun. Anahtarı kopyalayıp güvenli bir yere kaydedin; yetkili kullanıcılar anahtarın detay ekranından yeniden görüntüleyebilir.
  2. 2Anahtarı sunucunuzda bir ortam değişkenine koyun (MOONX_API_KEY) ve her isteğe Authorization başlığıyla ekleyin.
  3. 3İlk isteğinizi atın:
curl https://ich.panthersoft.com.tr/v1/contacts?pageSize=5 \
  -H "Authorization: Bearer $MOONX_API_KEY"

Başlarken

Kimlik doğrulama

Her istekte anahtarınızı Authorization başlığında Bearer olarak gönderin. Anahtar adresin (URL) içinde ya da çerezde kabul edilmez.

Başlık
Authorization: Bearer mx_live_a1b2c3d4e5f6_••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
Anahtar bir paroladır. Yalnızca kendi sunucunuzda saklayın; web sayfasına, mobil uygulamaya veya herkese açık bir depoya koymayın. Tarayıcıdan gelen istekler (Origin başlığı olanlar) bilerek reddedilir.

Yetkiler

Her anahtara yalnızca gereken yetkileri verin. Yetki olmadan ilgili uç 403 InsufficientScope döner.

YetkiNe yapar
contacts:readCarileri listeler ve okur
contacts:writeCari ekler, günceller, siler (okumayı da kapsar)
products:readÜrünleri, kategorileri, markaları ve birimleri okur
products:writeÜrün ekler, günceller, siler (okumayı da kapsar)
stock:readStok seviyelerini ve depoları okur
stock:writeDepolar arası stok transferi oluşturur (stok okumayı da kapsar)
invoices:readSatış ve alış faturalarını okur
invoices:writeSatış faturası oluşturur ve iptal eder (okumayı da kapsar)

Bir anahtar, onu oluşturan kullanıcının yetkisini aşamaz. Kullanıcının yetkisi alınır, firmadan çıkarılır veya hesabı kapatılırsa anahtarı da hemen çalışmaz.

Ek korumalar

  • İzinli IP adresleri: anahtarı yalnızca sunucunuzun IP adresiyle sınırlayın (tek adres ya da 198.51.100.0/24 gibi aralık).
  • Geçerlilik süresi: anahtara bitiş tarihi verin; dolunca otomatik geçersiz olur.
  • Anında iptal: Ayarlar → Entegrasyon bilgilerim sayfasından bir anahtarı sildiğiniz an çalışmaz. Sızdığından şüphelenirseniz önce iptal edin, sonra yenisini oluşturun.
  • Kayıt: ekleme, güncelleme ve silme istekleri hangi anahtarla, ne zaman ve hangi adresten yapıldığıyla kaydedilir; anahtarın Etkinlik ekranından görürsünüz.

Temel kavramlar

İstekler ve yanıtlar

  • Gövdesi olan isteklerde Content-Type: application/json kullanın. Gövde en fazla 1 MB olabilir.
  • Tanımlı olmayan bir alan göndermek 400 ile reddedilir; yazım hataları sessizce yutulmaz.
  • Tarihler ISO 8601, UTC biçimindedir (2026-10-20T09:12:00.000Z). Tarih filtreleri YYYY-AA-GG alır.
  • Tutarlar sayıdır, ondalık ayracı noktadır; para birimi ayrı bir alanda gelir (TRY, USD, EUR, GBP).
  • Tek kayıt { "data": { … } }, liste { "data": [ … ], "meta": { … } } biçiminde döner.

Sayfalama

Listeler page ve pageSize (1-100, varsayılan 25) ile sayfalanır. meta toplam kayıt ve sayfa sayısını verir.

Liste yanıtı
{
  "data": [ … ],
  "meta": { "page": 2, "pageSize": 25, "total": 183, "totalPages": 8 }
}

Temel kavramlar

Hatalar

Başarısız her istek uygun bir HTTP durum koduyla ve aynı biçimli bir gövdeyle döner. Koda bakarak karar verin; message insanlar içindir ve değişebilir. Destek talebinde requestId değerini paylaşın (yanıtta X-Request-Id başlığı olarak da gelir).

400 Bad Request
{
  "error": {
    "type": "InvalidRequest",
    "code": "ValidationFailed",
    "message": "Geçersiz istek: alanları kontrol edin.",
    "details": ["name should not be empty", "type must be one of the following values: CUSTOMER, SUPPLIER, BOTH"],
    "requestId": "req_5d1e9f7a2b66c3d4e5f60718"
  }
}
DurumKodAçıklama
400ValidationFailedAlanlar geçersiz. details dizisi hangi alanın neden reddedildiğini söyler.
400InvalidIdempotencyKeyIdempotency-Key 8-100 karakter olmalı (harf, rakam, - _ : .).
401InvalidApiKeyAnahtar eksik, bozuk ya da yanlış.
401ApiKeyRevokedAnahtar iptal edilmiş.
401ApiKeyExpiredAnahtarın süresi dolmuş.
402SubscriptionExpiredAbonelik veya deneme süresi bitti; okuma açık, yazma kapalıdır.
403InsufficientScopeAnahtarın bu işlem için yetkisi yok.
403IpNotAllowedİstek, anahtarın izinli IP listesinde olmayan bir adresten geldi.
403BrowserNotAllowedİstek tarayıcıdan geldi (Origin başlığı var). Anahtarlar yalnızca sunucudan kullanılır.
403KeyOwnerInactiveAnahtarı oluşturan kullanıcı artık aktif değil.
403KeyOwnerForbiddenAnahtarı oluşturan kullanıcının bu işlem için yetkisi kalmadı.
403CompanySuspendedFirma hesabı askıya alınmış.
404NotFoundKayıt bulunamadı.
409Conflictİşlem mevcut duruma aykırı (örn. hareketi olan cari silinemez).
409TransferNotPostedTransfer fişi açıldı ama kaydedilemedi (genelde kaynak depoda stok yetmedi); fiş taslak kaldı, details içinde documentId var.
409RequestInProgressAynı Idempotency-Key ile bir istek hâlâ işleniyor.
422IdempotencyKeyReuseIdempotency-Key farklı bir istek için kullanılmış.
429RateLimitedDakikalık istek sınırı aşıldı. Retry-After saniye sonra tekrar deneyin.
429TooManyFailedAttemptsBu IP'den çok fazla geçersiz anahtar denendi; geçici olarak kilitlendi.
500InternalErrorBeklenmeyen hata. requestId ile destek ekibine ulaşın.

5xx hatalarında ve ağ kesintilerinde isteği artan aralıklarla yeniden deneyin. Yazma isteklerinde yinelenmeyi önlemek için Idempotency-Key kullanın.

Temel kavramlar

Hız sınırı

Her anahtar için varsayılan sınır dakikada 300 istektir (anahtarı oluştururken 10-3000 arasında ayarlanır). Sınırın durumu her yanıtta gelir:

BaşlıkAnlamı
X-RateLimit-LimitDakikalık izin verilen istek sayısı
X-RateLimit-RemainingBu pencerede kalan istek
X-RateLimit-ResetPencerenin sıfırlanmasına kalan saniye
Retry-AfterYalnızca 429 yanıtında: kaç saniye sonra tekrar denenmeli

Çok sayıda kaydı çekerken pageSize=100 kullanın ve istekleri eşit aralıklara yayın.

Temel kavramlar

Tekrarlanan istekler

Bir POST isteği ağ hatası yüzünden yanıtsız kalırsa tekrar göndermek çift kayıt oluşturabilir. Idempotency-Key başlığı bunu önler: aynı anahtarla gelen aynı istek ikinci kez işlenmez, ilk sonuç aynen döner ve yanıtta Idempotent-Replayed: true bulunur.

curl
curl -X POST https://ich.panthersoft.com.tr/v1/contacts \
  -H "Authorization: Bearer $MOONX_API_KEY" \
  -H "Idempotency-Key: siparis-48213-cari" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Örnek Ticaret A.Ş.", "type": "CUSTOMER" }'
  • Anahtar 8-100 karakter olmalı; her işlem için benzersiz üretin (sipariş numaranız ya da bir UUID).
  • Aynı anahtar farklı gövdeyle kullanılırsa 422, ilk istek hâlâ sürüyorsa 409 döner.
  • Hata alan istek kaydedilmez; düzeltip aynı anahtarla tekrar deneyebilirsiniz. Kayıtlar 24 saat saklanır.

Entegrasyon

Stok ve ürün eşitleme

Stoğu başka bir sistemle (ERP, e-ticaret, depo yazılımı) eşit tutmak için önerilen yöntem: değişenleri periyodik olarak çekmek ve webhook ile anlık haber almak. İkisi birlikte kullanıldığında hiçbir değişiklik kaçmaz.

  1. İlk kurulum: GET /v1/variants?status=all ile tüm varyantları sayfa sayfa çekin ve kendi sisteminize yazın. status=all pasif ürünleri de getirir.
  2. Her tur: yalnızca değişenleri isteyin: updatedSince ile. Bir sonraki tur için kullanacağınız zaman, yanıttaki meta.asOf değerinden (sunucu saati) 2 dakika geridir; kendi saatinizi kullanmayın, saat farkı kayıp yaratır.
  3. Yazma işlemi idempotent olsun: aynı varyant iki kez gelirse sonuç aynı kalmalı. Çakışma payı bu yüzden güvenlidir.
  4. Günde bir tam sayım: updatedSince olmadan tüm varyantları karşılaştırın. Silinen kayıtlar değişenler listesinde görünmez; tam sayım bunları yakalar.
Node.js
const BASE = "https://ich.panthersoft.com.tr";
const headers = { Authorization: `Bearer ${process.env.MOONX_API_KEY}` };
let since = null; // son başarılı turun başlangıcı

async function sync() {
  const params = new URLSearchParams({ status: "all", pageSize: "100" });
  if (since) params.set("updatedSince", since);

  let page = 1;
  let asOf; // turun BAŞLANGICI: ilk sayfadaki sunucu saati
  for (;;) {
    params.set("page", String(page));
    const res = await (await fetch(`${BASE}/v1/variants?${params}`, { headers })).json();
    asOf ??= res.meta.asOf;
    for (const variant of res.data) await upsert(variant); // aynı kayıt iki kez gelse de sorun olmaz
    if (page >= res.meta.totalPages) break;
    page++;
  }
  // Çakışma payı: sunucu saatinden 2 dakika geri. Kaçırma ihtimali olmasın diye.
  since = new Date(Date.parse(asOf) - 2 * 60_000).toISOString();
}
Sıfır stok: /v1/variants hiç stok hareketi olmayan varyantı da onHand: 0 ile verir. /v1/stock ise stoğu sıfıra düşen depo satırını da döndürür (includeZero varsayılan true); yani sıfırlanan ürün asla "kaybolmaz".

Stok hangi alanı kullanmalı?

AlanAnlamı
onHandDepoda fiziksel olarak bulunan miktar
reservedSetlere (paketlere) ayrılmış ve tekli satışa kapalı miktar
availableSatılabilir miktar: onHand − reserved. Satış kanallarına bunu gönderin

Entegrasyon

Webhooklar

Webhook, MoonX'te bir şey değiştiğinde sizin sunucunuza anında HTTP POST atar. Olay sistemi sektörden bağımsızdır: her olay aynı zarfla gelir, yalnızca type ve data değişir.

  1. Ayarlar → Entegrasyon bilgilerim sayfasında bir webhook adresi ekleyin ve hangi olayları istediğinizi seçin. Adres https olmalıdır.
  2. Size bir imza sırrı (whsec_…) verilir. İsteklerin gerçekten MoonX'ten geldiğini bununla doğrularsınız.
  3. Test gönder ile adresinizi deneyin. Sunucunuz 10 saniye içinde 2xx dönmelidir.

İstek

Başlıklar
POST /hooks/moonx HTTP/1.1
Content-Type: application/json
User-Agent: MoonX-Webhooks/1
Webhook-Id: 6b1d3f0a-5a4e-4e0c-9d1f-2c7a8b9e0f11
Webhook-Timestamp: 1782736201
Webhook-Signature: v1=5d41402abc4b2a76b9719d911017c592e9d6c0a2c2b6e6e3f1a0b1c2d3e4f506
Webhook-Attempt: 1
Gövde
{
  "id": "6b1d3f0a-5a4e-4e0c-9d1f-2c7a8b9e0f11",
  "type": "stock.changed",
  "sequence": 18342,
  "createdAt": "2026-10-29T12:30:01.114Z",
  "resource": { "type": "variant", "id": "v1" },
  "data": {
    "variantId": "v1",
    "productId": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66",
    "code": "TSH-001-KRM-M",
    "barcode": "8680000000011",
    "unit": "ADET",
    "warehouseId": "w1",
    "previousOnHand": 145,
    "onHand": 140
  }
}
AlanAçıklama
idOlayın benzersiz kimliği. Aynı olay yeniden denemelerde aynı id ile gelir; tekrarı bununla ayıklayın.
sequenceArtan sıra numarası. Olaylar sırasız ulaşabilir: bir varyant+depo için elinizdeki en yüksek sequence'tan küçük olanı yok sayın.
typeOlay türü (aşağıdaki katalog)
createdAtOlayın gerçekleştiği an (UTC)
resourceOlayın ilgili olduğu kayıt (tür ve kimlik)
dataOlaya özgü içerik

Teslim ve yeniden deneme

  • 2xx dışında bir yanıt, zaman aşımı veya bağlantı hatası başarısız sayılır ve şu aralıklarla yeniden denenir: 10 sn, 30 sn, 2 dk, 10 dk, 30 dk, 2 sa, 6 sa, 12 sa (toplam 9 deneme, yaklaşık 21 saat).
  • Yönlendirmeler (3xx) takip edilmez. Adresiniz 410 Gone dönerse yeniden denenmez ve adres durdurulur.
  • Art arda 25 teslim kalıcı olarak başarısız olursa adres otomatik durdurulur; panelden sorunu giderip yeniden etkinleştirirsiniz. Başarısız teslimleri panelden tek tek yeniden deneyebilirsiniz.
  • Olaylar değişiklikle aynı işlemde kaydedilir; MoonX sunucusu kapansa bile olay kaybolmaz. Yine de webhook bir sinyaldir: periyodik eşitleme ile birlikte kullanın.
  • Önce hızlıca 2xx dönüp işi arka planda yapın; yavaş yanıt yeniden denemeye yol açar.
Adresiniz halka açık olmalıdır. İç ağ adresleri (10.x, 192.168.x, localhost vb.) ve iç ağa çözümlenen alan adları güvenlik gereği reddedilir. Yerel geliştirmede ngrok gibi bir tünel kullanın.

Entegrasyon

İmza doğrulama

Her istek Webhook-Signature: v1=… başlığıyla imzalanır. İmza, {timestamp}.{id}.{gövde} metninin sırrınızla alınmış HMAC-SHA256 özetidir. Doğrularken ham gövdeyi (JSON olarak ayrıştırılmadan) kullanın ve imzayı sabit zamanlı karşılaştırın. 5 dakikadan eski istekleri reddedin.

import crypto from "node:crypto";

// rawBody: istek gövdesi, JSON.parse edilmeden ÖNCE ham metin olarak
export function verifyMoonX(rawBody, headers, secret) {
  const id = headers["webhook-id"];
  const timestamp = Number(headers["webhook-timestamp"]);
  const received = String(headers["webhook-signature"] ?? "");
  if (!id || !Number.isFinite(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false; // 5 dakikadan eski: yeniden oynatma

  const expected = "v1=" + crypto.createHmac("sha256", secret).update(`${timestamp}.${id}.${rawBody}`).digest("hex");
  return received.split(" ").some((s) => s.length === expected.length && crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}

Sırrı kaybederseniz ya da sızdığından şüphelenirseniz panelden Sırrı yenileyin; eskisi hemen geçersiz olur. Sırrı yalnızca sunucunuzda saklayın.

Entegrasyon

Olay kataloğu

OlayNe zaman
stock.changedBir varyantın bir depodaki stoğu değişti (satış, alış, sayım, transfer, iade, iptal dahil). Stoğu sıfıra düşen varyant da bu olayla bildirilir.
webhook.testPanelden "Test gönder" ile yollanır; abonelik gerektirmez.

Katalog zamanla genişler; yeni olay türleri mevcut olayları bozmaz. Tanımadığınız bir type gelirse 2xx dönüp yok sayın, abone olmadığınız olay zaten gönderilmez.

API başvurusu

Kaynaklar

Aşağıdaki uçların hepsi /v1 altındadır. Her uçta gereken yetki sağ üstte gösterilir.

Cariler

Müşteri ve tedarikçiler. Bakiye, e-Fatura mükellefiyeti ve banka hesapları cari ile birlikte gelir.

GET

/v1/contacts

contacts:read

Carileri listele

Sorgu parametreleri

pageinteger

Sayfa numarası. Varsayılan 1.

pageSizeinteger

Sayfa başına kayıt, 1-100. Varsayılan 25.

searchstring

Unvan, tabela adı veya vergi/TC numarasında arar.

typeenum

CUSTOMER, SUPPLIER veya BOTH.

entityTypeenum

COMPANY, INDIVIDUAL, END_CONSUMER, ASSOCIATION, GOVERNMENT, FOUNDATION.

statusenum

active (varsayılan), archived veya all.

sortByenum

name, createdAt veya balance.

sortDirenum

asc veya desc.

İstek · curl
curl "https://ich.panthersoft.com.tr/v1/contacts?pageSize=10&status=active" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{
  "data": [
    {
      "id": "6f1c2b9e-3a47-4c1e-9d55-0a7e3f2b8c10",
      "name": "Örnek Ticaret A.Ş.",
      "lastName": null,
      "tradeName": null,
      "type": "CUSTOMER",
      "entityType": "COMPANY",
      "email": "muhasebe@ornek.com",
      "phone": "+90 212 000 00 00",
      "taxNumber": "1234567890",
      "taxOffice": "Maslak",
      "address": { "line": "Büyükdere Cad. No:1", "district": "Sarıyer", "city": "İstanbul", "postalCode": "34485", "country": "Türkiye" },
      "eInvoice": { "isTaxpayer": true, "alias": "urn:mail:defaultpk@ornek.com", "despatchAlias": null },
      "currency": "TRY",
      "creditLimit": 50000,
      "openingBalance": 0,
      "balance": 12450.5,
      "isActive": true,
      "bankAccounts": [{ "id": "b1", "iban": "TR330006100519786457841326", "bankName": "Türkiye İş Bankası", "currency": "TRY" }],
      "createdAt": "2026-10-12T08:30:00.000Z",
      "updatedAt": "2026-10-28T14:05:12.000Z"
    }
  ],
  "meta": { "page": 1, "pageSize": 25, "total": 1, "totalPages": 1 }
}
GET

/v1/contacts/{id}

contacts:read

Cariyi getir

  • balance: pozitif değer carinin size borcunu, negatif değer sizin cariye borcunuzu gösterir.
İstek · curl
curl "https://ich.panthersoft.com.tr/v1/contacts/{id}" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{ "data": {
    "id": "6f1c2b9e-3a47-4c1e-9d55-0a7e3f2b8c10",
    "name": "Örnek Ticaret A.Ş.",
    "lastName": null,
    "tradeName": null,
    "type": "CUSTOMER",
    "entityType": "COMPANY",
    "email": "muhasebe@ornek.com",
    "phone": "+90 212 000 00 00",
    "taxNumber": "1234567890",
    "taxOffice": "Maslak",
    "address": { "line": "Büyükdere Cad. No:1", "district": "Sarıyer", "city": "İstanbul", "postalCode": "34485", "country": "Türkiye" },
    "eInvoice": { "isTaxpayer": true, "alias": "urn:mail:defaultpk@ornek.com", "despatchAlias": null },
    "currency": "TRY",
    "creditLimit": 50000,
    "openingBalance": 0,
    "balance": 12450.5,
    "isActive": true,
    "bankAccounts": [{ "id": "b1", "iban": "TR330006100519786457841326", "bankName": "Türkiye İş Bankası", "currency": "TRY" }],
    "createdAt": "2026-10-12T08:30:00.000Z",
    "updatedAt": "2026-10-28T14:05:12.000Z"
  } }
POST

/v1/contacts

contacts:write

Cari oluştur

İstek gövdesi (JSON)

namestringzorunlu

Cari adı veya unvanı (en fazla 191).

typeenumzorunlu

CUSTOMER, SUPPLIER veya BOTH.

lastNamestring

Gerçek kişilerde soyad.

tradeNamestring

Tabela / ticari ad.

entityTypeenum

COMPANY, INDIVIDUAL, END_CONSUMER, ASSOCIATION, GOVERNMENT, FOUNDATION.

emailstring

Geçerli e-posta adresi.

phonestring

Telefon.

taxNumberstring

10 haneli VKN veya 11 haneli TCKN.

taxOfficestring

Vergi dairesi.

addressobject

line, district, city, postalCode, country.

eInvoiceobject

isTaxpayer, alias, despatchAlias. Mükellefiyet VKN/TCKN'den otomatik de bulunur.

currencyenum

TRY (varsayılan), USD, EUR, GBP. Hareket görmüş carinin para birimi değişmez.

creditLimitnumber

Risk limiti.

openingBalancenumber

Açılış bakiyesi (yalnızca oluştururken).

bankAccountsarray

En fazla 10 adet: { iban, currency }.

İstek · curl
curl -X POST "https://ich.panthersoft.com.tr/v1/contacts" \
  -H "Authorization: Bearer $MOONX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Örnek Ticaret A.Ş.",
  "type": "CUSTOMER",
  "email": "muhasebe@ornek.com",
  "taxNumber": "1234567890",
  "taxOffice": "Maslak",
  "address": { "city": "İstanbul", "district": "Sarıyer" }
}'
Yanıt · 201 Created
{ "data": {
    "id": "6f1c2b9e-3a47-4c1e-9d55-0a7e3f2b8c10",
    "name": "Örnek Ticaret A.Ş.",
    "lastName": null,
    "tradeName": null,
    "type": "CUSTOMER",
    "entityType": "COMPANY",
    "email": "muhasebe@ornek.com",
    "phone": "+90 212 000 00 00",
    "taxNumber": "1234567890",
    "taxOffice": "Maslak",
    "address": { "line": "Büyükdere Cad. No:1", "district": "Sarıyer", "city": "İstanbul", "postalCode": "34485", "country": "Türkiye" },
    "eInvoice": { "isTaxpayer": true, "alias": "urn:mail:defaultpk@ornek.com", "despatchAlias": null },
    "currency": "TRY",
    "creditLimit": 50000,
    "openingBalance": 0,
    "balance": 12450.5,
    "isActive": true,
    "bankAccounts": [{ "id": "b1", "iban": "TR330006100519786457841326", "bankName": "Türkiye İş Bankası", "currency": "TRY" }],
    "createdAt": "2026-10-12T08:30:00.000Z",
    "updatedAt": "2026-10-28T14:05:12.000Z"
  } }
PATCH

/v1/contacts/{id}

contacts:write

Cariyi güncelle

Yalnızca gönderdiğiniz alanlar değişir. Bir metin alanını silmek için boş metin ("") gönderin.

İstek gövdesi (JSON)

…

Oluşturmadaki alanların hepsi isteğe bağlıdır (openingBalance hariç).

isActiveboolean

false gönderilirse cari arşivlenir, true ile geri açılır.

bankAccountsarray

Gönderilirse mevcut liste bu liste ile değiştirilir.

İstek · curl
curl -X PATCH "https://ich.panthersoft.com.tr/v1/contacts/{id}" \
  -H "Authorization: Bearer $MOONX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phone": "+90 212 111 22 33", "creditLimit": 75000 }'
Yanıt · 200 OK
{ "data": {
    "id": "6f1c2b9e-3a47-4c1e-9d55-0a7e3f2b8c10",
    "name": "Örnek Ticaret A.Ş.",
    "lastName": null,
    "tradeName": null,
    "type": "CUSTOMER",
    "entityType": "COMPANY",
    "email": "muhasebe@ornek.com",
    "phone": "+90 212 000 00 00",
    "taxNumber": "1234567890",
    "taxOffice": "Maslak",
    "address": { "line": "Büyükdere Cad. No:1", "district": "Sarıyer", "city": "İstanbul", "postalCode": "34485", "country": "Türkiye" },
    "eInvoice": { "isTaxpayer": true, "alias": "urn:mail:defaultpk@ornek.com", "despatchAlias": null },
    "currency": "TRY",
    "creditLimit": 50000,
    "openingBalance": 0,
    "balance": 12450.5,
    "isActive": true,
    "bankAccounts": [{ "id": "b1", "iban": "TR330006100519786457841326", "bankName": "Türkiye İş Bankası", "currency": "TRY" }],
    "createdAt": "2026-10-12T08:30:00.000Z",
    "updatedAt": "2026-10-28T14:05:12.000Z"
  } }
DELETE

/v1/contacts/{id}

contacts:write

Cariyi sil

Yalnızca hiç işlem görmemiş cari silinebilir. Hareketi, faturası veya tahsilatı olan cari için 409 Conflict döner; bunun yerine arşivleyin.

İstek · curl
curl -X DELETE "https://ich.panthersoft.com.tr/v1/contacts/{id}" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{ "data": { "id": "6f1c2b9e-3a47-4c1e-9d55-0a7e3f2b8c10", "deleted": true } }

Ürünler

Ürün ve hizmet kartları. API ile sade (varyantsız) ürünler oluşturulur ve güncellenir; varyantlı ve setli ürünler okunabilir, panelden yönetilir. Panelde "Entegrasyona yayınla" kapalı olan ürün ve hizmetler API'de (ürünler, varyantlar, stok, faturaya ve transfere konu olma) ve webhook'larda hiç görünmez; bunlar için 404 döner.

GET

/v1/products

products:read

Ürünleri listele

Sorgu parametreleri

pageinteger

Sayfa numarası. Varsayılan 1.

pageSizeinteger

Sayfa başına kayıt, 1-100. Varsayılan 25.

searchstring

Ürün adı, stok kodu (varyant dahil) veya barkodda arar.

typeenum

PRODUCT veya SERVICE.

statusenum

active (varsayılan), archived veya all.

categoryIdstring

Kategoriye göre süz.

brandIdstring

Markaya göre süz.

sortByenum

name, code, salePrice veya createdAt.

sortDirenum

asc veya desc.

  • Listede özet alanlar döner; açıklama ve varyant ayrıntıları için tek ürünü getirin.
İstek · curl
curl "https://ich.panthersoft.com.tr/v1/products?pageSize=10&search=tisort" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{
  "data": [
    {
      "id": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66",
      "code": "TSH-001",
      "name": "Basic Tişört",
      "type": "PRODUCT",
      "barcode": "8680000000011",
      "isActive": true,
      "category": { "id": "c1", "name": "Giyim" },
      "brand": { "id": "b1", "name": "Moon" },
      "unit": { "code": "ADET", "name": "Adet" },
      "vatRate": 20,
      "currency": "TRY",
      "prices": { "purchase": 120, "sale": 249.9 },
      "hasVariants": false,
      "variantCount": 1,
      "createdAt": "2026-10-01T09:00:00.000Z"
    }
  ],
  "meta": { "page": 1, "pageSize": 25, "total": 1, "totalPages": 1 }
}
GET

/v1/products/{id}

products:read

Ürünü getir

İstek · curl
curl "https://ich.panthersoft.com.tr/v1/products/{id}" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{ "data": {
    "id": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66",
    "code": "TSH-001",
    "name": "Basic Tişört",
    "type": "PRODUCT",
    "isActive": true,
    "category": { "id": "c1", "name": "Giyim" },
    "brand": { "id": "b1", "name": "Moon" },
    "unit": { "id": "u1", "code": "ADET", "name": "Adet" },
    "vatRate": 20,
    "currency": "TRY",
    "prices": { "purchase": 120, "list": 299.9, "sale": 249.9, "wholesale": 199.9 },
    "shortDescription": "%100 pamuk",
    "description": null,
    "gtipCode": null,
    "hasVariants": false,
    "variants": [
      { "id": "v1", "code": "TSH-001", "barcode": "8680000000011", "label": "Standart", "isActive": true, "prices": { "purchase": 120, "list": 299.9, "sale": 249.9, "wholesale": 199.9 } }
    ],
    "createdAt": "2026-10-01T09:00:00.000Z",
    "updatedAt": "2026-10-20T11:42:00.000Z"
  } }
POST

/v1/products

products:write

Ürün oluştur

İstek gövdesi (JSON)

typeenumzorunlu

PRODUCT veya SERVICE.

namestringzorunlu

Ürün adı (en fazla 191).

unitIdstringzorunlu

Birim kimliği (GET /v1/units).

vatRateintegerzorunlu

KDV oranı (0-100); sistemde tanımlı oranlardan biri olmalı.

codestring

Stok kodu. Ürünlerde zorunlu, hizmetlerde boşsa otomatik üretilir. Firma içinde benzersiz.

barcodestring

Barkod.

categoryIdstring

Kategori kimliği (GET /v1/categories).

brandIdstring

Marka kimliği (GET /v1/brands).

shortDescriptionstring

En fazla 500 karakter.

descriptionstring

Uzun açıklama.

gtipCodestring

GTİP kodu (ihracat için).

currencyenum

TRY (varsayılan), USD, EUR, GBP.

pricesobject

purchase, list, sale, wholesale (4 ondalığa kadar).

İstek · curl
curl -X POST "https://ich.panthersoft.com.tr/v1/products" \
  -H "Authorization: Bearer $MOONX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "type": "PRODUCT",
  "code": "TSH-001",
  "name": "Basic Tişört",
  "unitId": "u1",
  "vatRate": 20,
  "prices": { "purchase": 120, "sale": 249.9 }
}'
Yanıt · 201 Created
{ "data": {
    "id": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66",
    "code": "TSH-001",
    "name": "Basic Tişört",
    "type": "PRODUCT",
    "isActive": true,
    "category": { "id": "c1", "name": "Giyim" },
    "brand": { "id": "b1", "name": "Moon" },
    "unit": { "id": "u1", "code": "ADET", "name": "Adet" },
    "vatRate": 20,
    "currency": "TRY",
    "prices": { "purchase": 120, "list": 299.9, "sale": 249.9, "wholesale": 199.9 },
    "shortDescription": "%100 pamuk",
    "description": null,
    "gtipCode": null,
    "hasVariants": false,
    "variants": [
      { "id": "v1", "code": "TSH-001", "barcode": "8680000000011", "label": "Standart", "isActive": true, "prices": { "purchase": 120, "list": 299.9, "sale": 249.9, "wholesale": 199.9 } }
    ],
    "createdAt": "2026-10-01T09:00:00.000Z",
    "updatedAt": "2026-10-20T11:42:00.000Z"
  } }
PATCH

/v1/products/{id}

products:write

Ürünü güncelle

Yalnızca gönderdiğiniz alanlar değişir.

İstek gövdesi (JSON)

…

Oluşturmadaki alanların hepsi isteğe bağlıdır (type hariç, değişmez).

isActiveboolean

false gönderilirse ürün arşivlenir, true ile geri açılır.

İstek · curl
curl -X PATCH "https://ich.panthersoft.com.tr/v1/products/{id}" \
  -H "Authorization: Bearer $MOONX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "prices": { "sale": 229.9 } }'
Yanıt · 200 OK
{ "data": {
    "id": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66",
    "code": "TSH-001",
    "name": "Basic Tişört",
    "type": "PRODUCT",
    "isActive": true,
    "category": { "id": "c1", "name": "Giyim" },
    "brand": { "id": "b1", "name": "Moon" },
    "unit": { "id": "u1", "code": "ADET", "name": "Adet" },
    "vatRate": 20,
    "currency": "TRY",
    "prices": { "purchase": 120, "list": 299.9, "sale": 249.9, "wholesale": 199.9 },
    "shortDescription": "%100 pamuk",
    "description": null,
    "gtipCode": null,
    "hasVariants": false,
    "variants": [
      { "id": "v1", "code": "TSH-001", "barcode": "8680000000011", "label": "Standart", "isActive": true, "prices": { "purchase": 120, "list": 299.9, "sale": 249.9, "wholesale": 199.9 } }
    ],
    "createdAt": "2026-10-01T09:00:00.000Z",
    "updatedAt": "2026-10-20T11:42:00.000Z"
  } }
DELETE

/v1/products/{id}

products:write

Ürünü sil

Stok hareketi veya belgesi olan ürün silinemez (409 Conflict); bunun yerine arşivleyin.

İstek · curl
curl -X DELETE "https://ich.panthersoft.com.tr/v1/products/{id}" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{ "data": { "id": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66", "deleted": true } }

Varyantlar

Entegrasyonlar için düz varyant listesi: her satır tek bir satılabilir birim (renk/beden gibi nitelikleriyle), barkodu, fiyatı ve stoğu ile gelir. Stok eşitleme için önerilen uçtur.

GET

/v1/variants

products:read

Varyantları listele

Stok alanı (stock) yalnızca anahtarda stock:read yetkisi de varsa gelir. Hiç stok hareketi olmayan varyant 0 stokla gelir; hizmetlerde stock null'dır. Setler (BUNDLE) bu listede yoktur. Ürünün özel alanları (örn. Sezon, Fatura ürün adı) customFields dizisinde { name, value } olarak gelir.

Sorgu parametreleri

pageinteger

Sayfa numarası. Varsayılan 1.

pageSizeinteger

Sayfa başına kayıt, 1-100. Varsayılan 25.

updatedSincedatetime

Yalnızca bu andan sonra değişenler: varyant, ürün ya da stok güncellenmiş olabilir. Bir sonraki çağrı için yanıttaki meta.asOf değerini kullanın.

statusenum

active (varsayılan), archived veya all. Eşitleme için all kullanın ki pasife alınanları da görün.

warehouseIdstring

Stok yalnızca bu depo için hesaplanır.

typeenum

PRODUCT (yalnızca ürünler) veya SERVICE (yalnızca hizmetler). Verilmezse ikisi de gelir; her satırda type alanı vardır.

productIdstring

Tek ürünün varyantları.

barcodestring

Tam barkod eşleşmesi.

searchstring

Stok kodu, barkod, ürün adı veya ürün kodu.

  • Sıralama sabittir (kimliğe göre); sayfalar arasında kayıt atlamaz ya da tekrar etmez.
  • stock.byWarehouse yalnızca stok satırı olan depoları içerir; stock.onHand tüm yetkili depoların toplamıdır.
İstek · curl
curl "https://ich.panthersoft.com.tr/v1/variants?status=all&pageSize=100&updatedSince=2026-10-29T10:00:00Z" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{
  "data": [
    {
      "id": "v1",
      "productId": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66",
      "productCode": "TSH-001",
      "productName": "Basic Tişört",
      "type": "PRODUCT",
      "code": "TSH-001-KRM-M",
      "barcode": "8680000000011",
      "label": "Kırmızı / M",
      "attributes": [ { "type": "Renk", "value": "Kırmızı" }, { "type": "Beden", "value": "M" } ],
      "brand": { "id": "b1", "name": "Moon" },
      "category": { "id": "c1", "name": "Giyim" },
      "unit": { "code": "ADET", "name": "Adet" },
      "vatRate": 20,
      "currency": "TRY",
      "prices": { "purchase": 120, "list": 299.9, "sale": 249.9, "wholesale": 199.9 },
      "isActive": true,
      "stock": {
        "onHand": 140,
        "reserved": 12,
        "available": 128,
        "byWarehouse": [ { "warehouseId": "w1", "onHand": 140, "reserved": 12, "available": 128 } ]
      },
      "updatedAt": "2026-10-29T12:30:00.000Z"
    }
  ],
  "meta": { "page": 1, "pageSize": 100, "total": 1, "totalPages": 1, "asOf": "2026-10-29T12:31:07.412Z" }
}
GET

/v1/variants/{id}

products:read

Varyantı getir

İstek · curl
curl "https://ich.panthersoft.com.tr/v1/variants/{id}" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{ "data": {
    "id": "v1",
    "productId": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66",
    "productCode": "TSH-001",
    "productName": "Basic Tişört",
    "type": "PRODUCT",
    "code": "TSH-001-KRM-M",
    "barcode": "8680000000011",
    "label": "Kırmızı / M",
    "attributes": [ { "type": "Renk", "value": "Kırmızı" }, { "type": "Beden", "value": "M" } ],
    "brand": { "id": "b1", "name": "Moon" },
    "category": { "id": "c1", "name": "Giyim" },
    "unit": { "code": "ADET", "name": "Adet" },
    "vatRate": 20,
    "currency": "TRY",
    "prices": { "purchase": 120, "list": 299.9, "sale": 249.9, "wholesale": 199.9 },
    "isActive": true,
    "stock": {
      "onHand": 140,
      "reserved": 12,
      "available": 128,
      "byWarehouse": [ { "warehouseId": "w1", "onHand": 140, "reserved": 12, "available": 128 } ]
    },
    "updatedAt": "2026-10-29T12:30:00.000Z"
  } }

Tanımlar

Ürün oluştururken kullanacağınız kimlikleri döndürür. Listeler küçüktür, sayfalanmaz.

GET

/v1/categories

products:read

Kategoriler

Sorgu parametreleri

kindenum

PRODUCT (varsayılan) veya SERVICE.

İstek · curl
curl "https://ich.panthersoft.com.tr/v1/categories?kind=PRODUCT" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{ "data": [ { "id": "c1", "name": "Giyim", "code": "GYM", "parentId": null, "kind": "PRODUCT", "isActive": true } ] }
GET

/v1/brands

products:read

Markalar

İstek · curl
curl "https://ich.panthersoft.com.tr/v1/brands" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{ "data": [ { "id": "b1", "name": "Moon", "code": "MOON", "isActive": true } ] }
GET

/v1/units

products:read

Birimler

İstek · curl
curl "https://ich.panthersoft.com.tr/v1/units" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{ "data": [ { "id": "u1", "code": "ADET", "name": "Adet", "isActive": true } ] }

Stok ve depolar

Depo ve varyant bazında eldeki ve kullanılabilir miktar. Yalnızca okunur.

GET

/v1/warehouses

stock:read

Depoları listele

  • Anahtarı oluşturan kullanıcının erişebildiği depolar döner.
İstek · curl
curl "https://ich.panthersoft.com.tr/v1/warehouses" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{
  "data": [
    {
      "id": "w1",
      "code": "MRK",
      "name": "Merkez Depo",
      "address": { "line": "Organize Sanayi 3. Cad.", "district": "Tuzla", "city": "İstanbul", "country": "Türkiye" },
      "isDefault": true,
      "isActive": true,
      "allowNegativeStock": false
    }
  ]
}
GET

/v1/stock

stock:read

Stok seviyeleri

Depo × varyant bazında stok. Stoğu sıfıra düşen satırlar da gelir, böylece sıfırlanan ürünü kaçırmazsınız. available = onHand − reserved (reserved: setlere ayrılan miktar).

Sorgu parametreleri

pageinteger

Sayfa numarası. Varsayılan 1.

pageSizeinteger

Sayfa başına kayıt, 1-100. Varsayılan 25.

updatedSincedatetime

Yalnızca bu andan sonra değişen satırlar (ISO 8601). Bir sonraki çağrı için yanıttaki meta.asOf değerini kullanın.

includeZeroboolean

Varsayılan true. false verilirse stoğu sıfır olan satırlar gelmez.

warehouseIdstring

Tek depoya göre süz.

variantIdstring

Tek varyantın depo satırları.

searchstring

Ürün adı, stok kodu veya barkod.

  • Hiç stok hareketi görmemiş bir varyantın satırı yoktur; tüm varyantları sıfır stokla birlikte almak için GET /v1/variants kullanın.
  • Yalnızca anahtarı oluşturan kullanıcının yetkili olduğu depolar gelir (firma sahibi tümünü görür).
İstek · curl
curl "https://ich.panthersoft.com.tr/v1/stock?pageSize=100&updatedSince=2026-10-29T10:00:00Z" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{
  "data": [
    {
      "productId": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66",
      "variantId": "v1",
      "productName": "Basic Tişört",
      "code": "TSH-001-KRM-M",
      "barcode": "8680000000011",
      "label": "Kırmızı / M",
      "unit": "ADET",
      "warehouse": { "id": "w1", "name": "Merkez Depo", "code": "MRK" },
      "onHand": 140,
      "reserved": 12,
      "available": 128,
      "updatedAt": "2026-10-29T12:30:00.000Z"
    }
  ],
  "meta": { "page": 1, "pageSize": 100, "total": 1, "totalPages": 1, "asOf": "2026-10-29T12:31:07.412Z" }
}
GET

/v1/products/{id}/stock

stock:read

Ürünün stoğu

Tek ürünün varyant ve depo kırılımı. byWarehouse anahtarları depo kimlikleridir.

İstek · curl
curl "https://ich.panthersoft.com.tr/v1/products/{id}/stock" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{
  "data": {
    "totalOnHand": 140,
    "warehouses": [ { "id": "w1", "code": "MRK", "name": "Merkez Depo", "isActive": true } ],
    "variants": [ { "variantId": "v1", "total": 140, "byWarehouse": { "w1": 140 } } ]
  }
}
GET

/v1/stock-transfers

stock:read

Referansa göre transferler

Transfer oluştururken verdiğiniz reference ile açılmış, kaydedilmiş transferleri getirir. Bir siparişin depoda net olarak ne kadar taşındığını hesaplamak ve geri almayı güvenle yapmak için kullanılır.

Sorgu parametreleri

referencestringzorunlu

Transfer oluştururken gönderilen reference (en fazla 100).

İstek · curl
curl "https://ich.panthersoft.com.tr/v1/stock-transfers?reference=SIP-10045" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{
  "data": [
    {
      "id": "0d4c…",
      "number": "TRF-000123",
      "status": "POSTED",
      "fromWarehouseId": "w1",
      "toWarehouseId": "w2",
      "reference": "SIP-10045",
      "createdAt": "2026-10-29T12:31:07.412Z",
      "lines": [ { "variantId": "v1", "quantity": 2 } ]
    }
  ]
}
POST

/v1/stock-transfers

stock:write

Depo transferi oluştur

İki depo arasında transfer fişi açar ve hemen kaydeder: stok kaynak depodan düşer, hedef depoya eklenir. Örneğin sipariş geldiğinde ürünü sevkiyat deposuna almak için kullanılır.

İstek gövdesi (JSON)

fromWarehouseIdstringzorunlu

Kaynak depo kimliği (GET /v1/stock yanıtındaki depolar).

toWarehouseIdstringzorunlu

Hedef depo kimliği.

linesarrayzorunlu

En fazla 500 satır: { variantId | barcode | code, quantity }. Varyant bu üç alandan biriyle belirtilir.

referencestring

Sizin sistemdeki karşılığı (sipariş no gibi); fişin açıklamasına yazılır (en fazla 100).

notestring

Serbest not (en fazla 500).

  • Her istekte Idempotency-Key gönderin: ağ hatasında aynı istek tekrarlanırsa ikinci bir transfer açılmaz.
  • Kaynak depoda stok yetmezse 409 TransferNotPosted döner ve fiş taslak olarak kalır (details içinde documentId); panelden görülüp silinebilir ya da tamamlanabilir.
  • Aynı varyant birden çok satırda gelirse miktarlar toplanır. Bulunamayan ya da birden çok varyanta denk gelen satırlar 422 ValidationFailed ile toplu bildirilir.
İstek · curl
curl -X POST "https://ich.panthersoft.com.tr/v1/stock-transfers" \
  -H "Authorization: Bearer $MOONX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "fromWarehouseId": "w1",
  "toWarehouseId": "w2",
  "reference": "SIP-10045",
  "lines": [
    { "barcode": "8690000000011", "quantity": 2 },
    { "code": "TS-KRM-M", "quantity": 1 }
  ]
}'
Yanıt · 201 Created
{
  "data": {
    "id": "0d4c…",
    "number": "TRF-000123",
    "status": "POSTED",
    "fromWarehouseId": "w1",
    "toWarehouseId": "w2",
    "reference": "SIP-10045",
    "lines": [ { "variantId": "v1", "quantity": 2 }, { "variantId": "v7", "quantity": 1 } ]
  }
}

Faturalar

Satış ve alış faturaları. Okunur; ayrıca siparişten satış faturası oluşturulur ve iptal edilir. e-Belge gönderimi panelden yapılır.

POST

/v1/invoices

invoices:write

Satış faturası oluştur

Onaylı bir satış faturası kesilir: stok belirtilen depodan düşer, cari bakiye ve KDV kayıtları işlenir. Cari yoksa faturayla birlikte açılır. Her şey tek işlem gibi çalışır: fatura oluşmazsa bu çağrıda açılan cari arşive alınır (silinmez), stok ve bakiye değişmez.

İstek gövdesi (JSON)

warehouseIdstringzorunlu

Stoğun düşeceği depo kimliği.

referencestringzorunlu

Sizin sistemdeki sipariş numarası (en fazla 60). Aynı reference ile ikinci fatura kesilmez; mevcut fatura döner (duplicate: true).

linesarrayzorunlu

En fazla 500 satır: { variantId | barcode | code, quantity, unitPrice (KDV dahil), vatRate?, description? }. vatRate verilmezse ürünün KDV oranı kullanılır.

contactIdstring

Mevcut cari. contactId ya da contact'tan biri zorunludur.

contactobject

{ name, lastName?, email?, phone?, taxNumber?, taxOffice?, address? }. Önce vergi/TC no, sonra e-posta, sonra telefonla mevcut cari aranır; arşivdeki eşleşme yeniden aktifleştirilir; yoksa yeni cari açılır.

currencyenum

TRY (varsayılan), USD, EUR, GBP. Döviz için exchangeRate zorunludur.

descriptionstring

Fatura açıklaması.

isInternetSaleboolean

İnternet satışı. true ise websiteUrl zorunludur.

websiteUrlstring

Satışın yapıldığı site.

paymentMethodstring

Ödeme yöntemi.

shipmentobject

Kargo bilgisi (internet satışında e-belgeye yazılır): { carrierName, carrierTaxNumber?, trackingNumber?, date? }. Takip numarası açıklamaya eklenir.

microExportobject

Mikro ihracat: { deliveryCountry, deliveryCity?, deliveryDistrict?, deliveryStreet? }. Tüm satırlar KDV %0 ve istisna sebebi 301 ile kesilir; müşterinin ülkesi (contact.address.country) yurtdışı olmalıdır.

exchangeRatenumber

currency TRY dışındaysa zorunlu: 1 birim dövizin TL karşılığı.

  • Yanıt, GET /v1/invoices/{id} ile aynı alanları ve ek olarak duplicate ile contactCreated'ı içerir.
  • Her istekte Idempotency-Key gönderin. Ayrıca aynı reference ikinci fatura kesmez.
  • Fatura MoonX'te kayıt olarak tutulur; e-Belge MoonX'ten gönderilmez. Yasal belgeyi başka bir entegratör kesiyorsa çift belge oluşmaz.
  • Depoda stok yetmezse 409/422 döner ve hiçbir kayıt değişmez (bu çağrıda açılan cari arşive alınır).
İstek · curl
curl -X POST "https://ich.panthersoft.com.tr/v1/invoices" \
  -H "Authorization: Bearer $MOONX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "warehouseId": "w2",
  "reference": "SIP-10045",
  "contact": { "name": "Ayşe Yılmaz", "email": "ayse@example.com", "taxNumber": "12345678901",
               "address": { "line": "Örnek Mah. 1. Sok. No:3", "district": "Kadıköy", "city": "İstanbul" } },
  "isInternetSale": true,
  "websiteUrl": "www.trendyol.com",
  "lines": [ { "barcode": "8690000000011", "quantity": 2, "unitPrice": 120 } ]
}'
Yanıt · 201 Created
{
  "data": {
    "id": "5b1e…",
    "number": "MX2026000000001",
    "status": "APPROVED",
    "duplicate": false,
    "contactCreated": true
  }
}
POST

/v1/invoices/{id}/return

invoices:write

İade faturası oluştur

Onaylı bir satış faturasının iadesini keser: ürünler seçilen depoya geri girer, cari alacaklandırılır. Fiyat ve KDV, iade edilen faturanın kalemlerinden alınır; hiçbir kalemde faturalanan miktardan fazla iade edilemez.

İstek gövdesi (JSON)

warehouseIdstringzorunlu

İade edilen ürünlerin gireceği depo kimliği.

referencestringzorunlu

Bu iadenin sizdeki kimliği (en fazla 60). Aynı reference ile ikinci iade faturası kesilmez; mevcut iade döner (duplicate: true).

linesarray

{ variantId | barcode | code, quantity }. Verilmezse faturanın henüz iade edilmemiş tüm miktarı iade edilir (kısmi iadede belirtin).

descriptionstring

Açıklama; boşsa "… nolu faturanın iadesi" yazılır.

  • Yanıt GET /v1/invoices/{id} ile aynı alanları ve ek olarak duplicate'i içerir.
  • İade yalnızca onaylı satış faturasına yapılır; iptal edilmiş fatura ya da başka bir iade faturası iade edilemez.
  • Fazla miktar 422 ValidationFailed döner ve hiçbir kayıt değişmez.
İstek · curl
curl -X POST "https://ich.panthersoft.com.tr/v1/invoices/{id}/return" \
  -H "Authorization: Bearer $MOONX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "warehouseId": "w1",
  "reference": "SIP-10045-IADE-1",
  "lines": [ { "barcode": "8690000000011", "quantity": 1 } ]
}'
Yanıt · 201 Created
{
  "data": {
    "id": "9a2f…",
    "number": "IF-000004",
    "status": "APPROVED",
    "isReturn": true,
    "duplicate": false
  }
}
POST

/v1/invoices/{id}/cancel

invoices:write

Faturayı iptal et

Faturanın stok ve cari etkisini geri alır; kayıt silinmez, iptal durumuna geçer. Resmileşmiş (gönderilmiş) e-belge iptal edilemez.

İstek · curl
curl -X POST "https://ich.panthersoft.com.tr/v1/invoices/{id}/cancel" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 201 Created
{ "data": { "id": "5b1e…", "cancelled": true } }
GET

/v1/invoices

invoices:read

Faturaları listele

Sorgu parametreleri

directionenumzorunlu

SALES (satış) veya PURCHASE (alış).

pageinteger

Sayfa numarası. Varsayılan 1.

pageSizeinteger

Sayfa başına kayıt, 1-100. Varsayılan 25.

statusenum

DRAFT, APPROVED veya CANCELLED.

paymentStatusenum

OPEN, PARTIAL, PAID veya UNPAID (açık + kısmi).

contactIdstring

Cariye göre süz.

dateFromdate

YYYY-AA-GG, bu tarih dahil.

dateTodate

YYYY-AA-GG, bu tarih dahil.

searchstring

Fatura no, cari adı, açıklama, sipariş no, ürün kodu veya barkodda arar.

sortByenum

number, date veya dueDate.

sortDirenum

asc veya desc.

  • summary.totalTry: filtredeki onaylı faturaların TL toplamı (iadeler düşülür).
İstek · curl
curl "https://ich.panthersoft.com.tr/v1/invoices?direction=SALES&dateFrom=2026-10-01&pageSize=10" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{
  "data": [
    {
      "id": "i1",
      "direction": "SALES",
      "number": "MXA2026000000123",
      "status": "APPROVED",
      "documentType": "E_INVOICE",
      "isReturn": false,
      "date": "2026-10-20T00:00:00.000Z",
      "dueDate": "2026-11-20T00:00:00.000Z",
      "contact": { "id": "6f1c2b9e-3a47-4c1e-9d55-0a7e3f2b8c10", "name": "Örnek Ticaret A.Ş." },
      "currency": "TRY",
      "grandTotal": 2998.8,
      "paymentStatus": "PARTIAL",
      "paidAmount": 1000,
      "eDocumentStatus": "APPROVED",
      "description": null,
      "createdAt": "2026-10-20T09:12:00.000Z",
      "updatedAt": "2026-10-20T09:14:00.000Z"
    }
  ],
  "meta": { "page": 1, "pageSize": 25, "total": 1, "totalPages": 1 },
  "summary": { "totalTry": 2998.8 }
}
GET

/v1/invoices/{id}

invoices:read

Faturayı getir

Liste alanlarına ek olarak tutar kırılımı, cari ayrıntısı, satırlar ve faturayı kapatan tahsilat/ödemeler döner.

İstek · curl
curl "https://ich.panthersoft.com.tr/v1/invoices/{id}" \
  -H "Authorization: Bearer $MOONX_API_KEY"
Yanıt · 200 OK
{
  "data": {
    "id": "i1",
    "direction": "SALES",
    "number": "MXA2026000000123",
    "status": "APPROVED",
    "documentType": "E_INVOICE",
    "isReturn": false,
    "date": "2026-10-20T00:00:00.000Z",
    "dueDate": "2026-11-20T00:00:00.000Z",
    "currency": "TRY",
    "grandTotal": 2998.8,
    "paymentStatus": "PARTIAL",
    "paidAmount": 1000,
    "ettn": "8f1e2d3c-4b5a-6978-8a9b-0c1d2e3f4a5b",
    "exchangeRate": 1,
    "vatIncluded": false,
    "subtotal": 2499,
    "discountTotal": 0,
    "vatTotal": 499.8,
    "withholdingTotal": 0,
    "grandTotalTry": 2998.8,
    "contact": {
      "id": "6f1c2b9e-3a47-4c1e-9d55-0a7e3f2b8c10",
      "name": "Örnek Ticaret A.Ş.",
      "taxNumber": "1234567890",
      "taxOffice": "Maslak",
      "address": { "line": "Büyükdere Cad. No:1", "district": "Sarıyer", "city": "İstanbul", "country": "Türkiye" },
      "email": "muhasebe@ornek.com",
      "phone": "+90 212 000 00 00"
    },
    "lines": [
      {
        "id": "l1",
        "productId": "0b9a5d7c-8e21-47f6-a3c4-5d1e9f7a2b66",
        "variantId": "v1",
        "code": "TSH-001",
        "barcode": "8680000000011",
        "name": "Basic Tişört",
        "label": "Standart",
        "unit": "Adet",
        "quantity": 10,
        "unitPrice": 249.9,
        "discountRate": 0,
        "vatRate": 20,
        "lineTotal": 2998.8,
        "description": null
      }
    ],
    "payments": [ { "type": "FINANCE_TRANSACTION", "documentNumber": "TH-0042", "date": "2026-10-22T00:00:00.000Z", "amount": 1000 } ]
  }
}

Rehber

Güvenlik önerileri

  • Her sistem için ayrı anahtar oluşturun. Biri sızarsa yalnızca onu iptal edersiniz, diğer entegrasyonlar etkilenmez.
  • En az yetki: yalnızca okuma yapan bir senkronizasyon için *:write vermeyin.
  • IP kısıtı koyun. Sunucunuzun çıkış IP'si sabitse en etkili korumadır.
  • Anahtarı kayda geçirmeyin: log, hata raporu ve kaynak kodda anahtar bulunmamalı. Ortam değişkeni veya gizli yönetim aracı kullanın.
  • Düzenli yenileyin. Süreli anahtar oluşturup dönemsel olarak yenisiyle değiştirin.
  • Sızıntıdan şüpheleniyorsanız anahtarı hemen iptal edin ve Etkinlik ekranında beklenmedik işlem olup olmadığına bakın.

Rehber

Sürümleme

Adresteki /v1 sürümü belirtir. Aynı sürümde yalnızca geriye uyumlu değişiklikler yapılır: yeni uçlar, yanıtlara yeni alanlar, yeni isteğe bağlı parametreler. Yazılımınız tanımadığı alanları yok saymalıdır. Geriye uyumsuz bir değişiklik gerekirse yeni bir sürüm (/v2) yayımlanır ve /v1 önceden duyurulan bir süre boyunca çalışmaya devam eder.

Sorularınız için panelden destek talebi açabilirsiniz.