Stok ve Fiyat Güncelleme

Barkod düzeyinde stok adedinin, satış fiyatının ve liste fiyatının güncellenmesini sağlar. İşlem asenkron olarak yürütülür: istek alındığında bir batchRequestId üretilir ve durumu daha sonra batch durum sorgulama endpoint'i üzerinden takip edilir.

Gerekli yetki: stock:write

Endpoint

POST /integration/inventory/sellers/{sellerId}/products/price-and-inventory

Production
https://api.milagron.com/integration/inventory/sellers/{sellerId}/products/price-and-inventory
Stage
https://stageapi.milagron.com/integration/inventory/sellers/{sellerId}/products/price-and-inventory

İstek Gövdesi

{
  "items": [
    {
      "barcode": "8690000000001",
      "quantity": 50,
      "salePrice": 299.90,
      "listPrice": 399.90
    },
    {
      "barcode": "8690000000002",
      "quantity": 10
    }
  ]
}

Alanlar

AlanTipZorunluAçıklama
itemsarrayEvetGüncellenecek ürünlerin listesi (en fazla 1000 adet).
items[].barcodestringEvet1–100 karakter aralığında olmalıdır.
items[].quantityintegerKoşullu0–9999 aralığında. Üç değerden en az birinin gönderilmesi zorunludur.
items[].salePricenumberKoşullu0 veya pozitif değer. Üç değerden en az birinin gönderilmesi zorunludur.
items[].listPricenumberKoşullu0 veya pozitif değer. Üç değerden en az birinin gönderilmesi zorunludur.

İş Kuralları

  • salePrice değeri, listPrice değerinden büyük olamaz.
  • salePrice ile listPrice birbirine eşit olduğunda, listPrice otomatik olarak 0'a indirilir (indirim olmadığı kabul edilir).
  • Maliyet (cost) değeri şu formülle hesaplanır: (salePrice − salePrice × komisyon ÷ 100) ÷ (taxRate ÷ 100 + 1).

Yanıt (200 OK)

{
  "batchRequestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Idempotency

15 dakikalık zaman dilimi içerisinde aynı payload ile tekrar istek gönderilmesi durumunda, aynı batchRequestId değeri döner. Bu davranış; ağ kesintisi gibi sebeplerle yeniden deneme yapan istemcilerin yinelenen güncellemelere yol açmasını engeller.

Kullanım Örnekleri

curl -u "API_KEY:API_SECRET" \
  -X POST "https://api.milagron.com/integration/inventory/sellers/123/products/price-and-inventory" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
        {
            "barcode": "8690000000001",
            "quantity": 50,
            "salePrice": 299.9,
            "listPrice": 399.9
        }
    ]
}'
<?php

$ch = curl_init('https://api.milagron.com/integration/inventory/sellers/123/products/price-and-inventory');

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_USERPWD        => 'API_KEY:API_SECRET',
    CURLOPT_CUSTOMREQUEST  => 'POST',
    CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS     => json_encode([
    'items' => [
        [
            'barcode' => '8690000000001',
            'quantity' => 50,
            'salePrice' => 299.9,
            'listPrice' => 399.9
        ]
    ]
]),
]);

$response = curl_exec($ch);
$data = json_decode($response, true);
curl_close($ch);
const auth = Buffer.from('API_KEY:API_SECRET').toString('base64');

const res = await fetch('https://api.milagron.com/integration/inventory/sellers/123/products/price-and-inventory', {
    method: 'POST',
    headers: {
        'Authorization': `Basic ${auth}`,
        'Content-Type':  'application/json'
    },
    body: JSON.stringify({
    items: [
        {
            barcode: '8690000000001',
            quantity: 50,
            salePrice: 299.9,
            listPrice: 399.9
        }
    ]
})
});

const data = await res.json();
import requests

response = requests.post(
    'https://api.milagron.com/integration/inventory/sellers/123/products/price-and-inventory',
    auth=('API_KEY', 'API_SECRET'),
    json={
    'items': [
        {
            'barcode': '8690000000001',
            'quantity': 50,
            'salePrice': 299.9,
            'listPrice': 399.9
        }
    ]
}
)

response.raise_for_status()
data = response.json()
package main

import (
    "bytes"
    "encoding/json"
    "net/http"
)

func main() {
    payload, _ := json.Marshal(map[string]interface{}{
    "items": []interface{}{
        map[string]interface{}{
            "barcode": "8690000000001",
            "quantity": 50,
            "salePrice": 299.9,
            "listPrice": 399.9,
        },
    },
})
    req, _ := http.NewRequest("POST", "https://api.milagron.com/integration/inventory/sellers/123/products/price-and-inventory", bytes.NewBuffer(payload))
    req.SetBasicAuth("API_KEY", "API_SECRET")
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
}
import java.net.URI;
import java.net.http.*;
import java.util.Base64;

HttpClient client = HttpClient.newHttpClient();

String auth = Base64.getEncoder()
    .encodeToString("API_KEY:API_SECRET".getBytes());

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.milagron.com/integration/inventory/sellers/123/products/price-and-inventory"))
    .header("Authorization", "Basic " + auth)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"items\":[{\"barcode\":\"8690000000001\",\"quantity\":50,\"salePrice\":299.9,\"listPrice\":399.9}]}"))
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://api.milagron.com/integration/inventory/sellers/123/products/price-and-inventory')

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri.request_uri)
request.basic_auth('API_KEY', 'API_SECRET')
request['Content-Type'] = 'application/json'
request.body = {
  items: [
    {
      barcode: '8690000000001',
      quantity: 50,
      salePrice: 299.9,
      listPrice: 399.9
    }
  ]
}.to_json

response = http.request(request)
data = JSON.parse(response.body)
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

var client = new HttpClient();

var auth = Convert.ToBase64String(
    Encoding.UTF8.GetBytes("API_KEY:API_SECRET"));
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Basic", auth);

var content = new StringContent(
    "{\"items\":[{\"barcode\":\"8690000000001\",\"quantity\":50,\"salePrice\":299.9,\"listPrice\":399.9}]}",
    Encoding.UTF8,
    "application/json");

var response = await client.PostAsync("https://api.milagron.com/integration/inventory/sellers/123/products/price-and-inventory", content);
var data = await response.Content.ReadAsStringAsync();

Hata Kodları

KodSebep
400items dizisi boş, eksik veya 1000 sınırı aşılmış.
401Kimlik doğrulama başarısız.
403Yetki yetersizliği, sellerId uyumsuzluğu veya ortam uyumsuzluğu.
422Doğrulama hatası (detaylı errors dizisi ile birlikte).
429Rate limit aşıldı.

Stage Ortamı Davranışı

Stage ortamında bu endpoint:
  • Doğrulama ve iş kurallarını gerçek ortamla aynı şekilde uygular.
  • Batch ve item kayıtlarını veritabanına yazar (environment='stage' etiketiyle).
  • Worker süreci, barkodun veritabanında bulunup bulunmadığını ve salePrice ≤ listPrice kuralını kontrol eder.
  • Stok ve fiyat verileri değiştirilmez, dış sistemlere çağrı gönderilmez.
  • Durum sorgulama endpoint'i, gerçekçi başarı/başarısızlık sonuçları döner.

Önerilen Polling Yaklaşımı

async function pollBatch(sellerId, batchId, auth) {
    const url = `https://api.milagron.com/integration/inventory/sellers/${sellerId}/products/batch-requests/${batchId}`;

    for (let i = 0; i < 30; i++) {
        await new Promise(r => setTimeout(r, 2000));

        const res = await fetch(url, { headers: { Authorization: `Basic ${auth}` } });
        const data = await res.json();

        if (data.status === 'completed' || data.status === 'failed') {
            return data;
        }
    }
    throw new Error('Batch timeout');
}