Partner API · v1 · wersja 1.5.1

Katalog, ceny, stany
i zamówienia przez API.

REST API do integracji Twojego sklepu, ERP-a lub aplikacji z katalogiem Akces Dekoracje. Katalog z cenami i stanami, a dla kont z włączonymi zamówieniami — składanie i śledzenie zamówień. Uwierzytelnianie kluczem, format JSON. Stabilny kontrakt v1: nowe pola, kody błędów i wartości statusów mogą dochodzić, a zmiany niezgodne wstecz ogłaszamy mailowo z wyprzedzeniem (zasady zgodności i historia zmian).

W przeglądarce przetestujesz odczyt (katalog, statusy). Zamówienia i walidację wysyłasz tylko z serwera, z podpisem HMAC — zob. instrukcję zamówień.

Co dostajesz

Katalog produktów z cenami i stanami, zsynchronizowany z naszym systemem ERP, a dla kont z włączonymi zamówieniami — składanie i śledzenie zamówień. Format JSON.

📦 Produkty

Cały katalog z paginacją

SKU wariantu i rodzica, nazwa, kod kreskowy (EAN), ścieżka kategorii, kolor, pakowanie (karton zbiorczy / pudełko / opakowanie — liczba jednostek w każdym) i krok zamawiania (orderStep), jednostka, cena katalogowa netto oraz Twoja cena (yourPriceNetto, konta z zamówieniami), dostępny stan (zamaskowany), objętość kartonu zbiorczego, wszystkie zdjęcia wariantu (główne pierwsze), znacznik ostatniej zmiany (updatedAt). Filtrowanie po SKU wariantu, SKU rodzica, nazwie i dacie zmiany.

🔐 Bezpieczeństwo

Klucz API + lista dozwolonych adresów IP

Każde żądanie jest uwierzytelniane kluczem. Dostęp może być ograniczony do uzgodnionych adresów IP. Dla kont z zamówieniami lista jest obowiązkowa i obejmuje wszystkie endpointy, także katalog. Zamówienia wymagają dodatkowo podpisu HMAC. Wszystkie żądania są rejestrowane. Stany magazynowe są maskowane.

🛒 Zamówienia

Składanie i śledzenie zamówień

Dla kont z włączonymi zamówieniami: walidacja próbna koszyka, złożenie zamówienia z podpisem HMAC, numer zamówienia w Akces i statusy realizacji. Obowiązują cena i dostępność Akces z chwili złożenia zamówienia. Pełna instrukcja →

8500+
Wariantów produktów dostępnych przez API
200
Maks. produktów na jednej stronie listy
60/min
Domyślny limit żądań katalogu (do podniesienia)

Szybki start

Trzy kroki, żeby zacząć pobierać dane.

1

Zdobądź klucz API

Skontaktuj się z nami pod adresem kontakt@akces.pl. Otrzymasz klucz w formacie pk_ + 32 znaki hex (np. pk_a1b2c3d4e5f6…) oraz parametry konta (limit żądań, lista dozwolonych adresów IP — obowiązkowa dla kont z zamówieniami).

2

Wyślij pierwsze żądanie

Każde żądanie do /v1/* wymaga nagłówka X-Partner-Key. Bazowy URL: https://api.akces.pl.

# Pobierz pierwsze 5 produktów
curl "https://api.akces.pl/v1/products?limit=5" \
  -H "X-Partner-Key: pk_TWOJ_KLUCZ"
const res = await fetch(
  "https://api.akces.pl/v1/products?limit=5",
  { headers: { "X-Partner-Key": process.env.AKCES_API_KEY } }
);
const { data, pagination } = await res.json();
console.log(`Mam ${pagination.total} produktów`);
// Wymagane: PHP 8+ z curl
$ch = curl_init("https://api.akces.pl/v1/products?limit=5");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ["X-Partner-Key: " . getenv("AKCES_API_KEY")],
]);
$data = json_decode(curl_exec($ch), true);
echo "Mam {$data['pagination']['total']} produktów\n";
import requests, os

r = requests.get(
    "https://api.akces.pl/v1/products",
    params={"limit": 5},
    headers={"X-Partner-Key": os.environ["AKCES_API_KEY"]},
)
data = r.json()
print(f"Mam {data['pagination']['total']} produktów")
3

Synchronizuj przyrostowo

Za pierwszym razem pobierz cały katalog (limit=200, kolejne strony). Potem dociągaj zmiany przez parametr updatedSince: podstaw pole timestamp z poprzedniej odpowiedzi minus 5 minut zapasu (odpowiedź może zawierać produkty bez zmian — przetwarzaj ją idempotentnie). updatedAt obejmuje zmiany danych produktu, stanów, cen katalogowych i zdjęć, ale nie Twojej ceny (yourPriceNetto — promocje, oferty, rabaty konta) ani rezerwacji, dlatego co 15–30 minut pobierz też pełną listę. Przed wysłaniem zamówienia sprawdź koszyk przez POST /v1/orders/validate.

# Zmiany od poprzedniego pobrania
# (updatedSince = pole timestamp z poprzedniej odpowiedzi minus 5 min)
curl "https://api.akces.pl/v1/products?updatedSince=2026-11-05T15:20:54Z&limit=200" \
  -H "X-Partner-Key: pk_TWOJ_KLUCZ"

# Co 15–30 min — pełna lista (kolejne strony: page=2, 3…)
curl "https://api.akces.pl/v1/products?limit=200&page=1" \
  -H "X-Partner-Key: pk_TWOJ_KLUCZ"

Endpointy

Pełny opis parametrów i schematów odpowiedzi znajdziesz w interaktywnej dokumentacji. Endpointy zamówień są dostępne dla kont z włączonymi zamówieniami — szczegóły niżej.

GET
/v1/products
Lista produktów z paginacją, posortowana rosnąco po SKU. Filtry: page, limit (maks. 200), sku, parentSku, search, updatedSince (data w formacie ISO 8601, inaczej 400).
GET
/v1/products/{sku}
Pojedynczy wariant po SKU. Zwraca 404, jeśli SKU jest nieznany lub produkt jest niedostępny.
POST
/v1/orders
Złożenie zamówienia (wymaga podpisu HMAC). Odpowiedź: 201 przyjęte, 202 czeka na zatwierdzenie, 422 odrzucone z listą błędów.
POST
/v1/orders/validate
Walidacja próbna — te same reguły co zamówienie, bez rezerwacji i zapisu. Idealna do testów integracji.
GET
/v1/orders
Twoje zamówienia i ich statusy. Filtry: updatedSince, externalOrderNumber, page, limit.
GET
/v1/orders/{id}
Status pojedynczego zamówienia (id z odpowiedzi POST).
GET
/v1
Nazwa i wersja API oraz adresy dokumentacji i specyfikacji OpenAPI. Bez uwierzytelniania.
GET
/health
Stan usługi: ok, degraded (katalog działa, zamówienia chwilowo niedostępne) albo error (HTTP 503). Bez uwierzytelniania — używaj do monitoringu (np. UptimeRobot, Pingdom).

Przykładowa odpowiedź

Pojedynczy produkt z /v1/products dla konta z włączonymi zamówieniami. Dane produktu są prawdziwe; cena, stan, ścieżka kategorii i data są przykładowe. Pola ean (kod kreskowy) i category (ścieżka kategorii) mogą być null, jeśli towar nie ma ich uzupełnionych. images zawiera wszystkie zdjęcia wariantu (główne pierwsze); imageUrl to zawsze pierwsze z nich, zachowane dla zgodności ze starszymi integracjami.

{
  "sku": "A02-003",
  "parentSku": "A02",
  "name": "Róża pianka główka 2 cm (144 szt.)",
  "ean": "5907489847698",        // kod kreskowy (EAN) z karty towaru
  "category": "Kwiaty sztuczne/Główki kwiatowe",   // pełna ścieżka kategorii (tu przykładowa)
  "colorName": "#003 red",
  "packaging": { "outerCarton": 120, "innerCarton": null, "package": 1 },   // liczba jednostek w kartonie zbiorczym / pudełku / opakowaniu
  "unit": "opak",
  "priceNetto": 10.95,                // cena katalogowa netto (przykładowa)
  "yourPriceNetto": 7.67,             // Twoja aktualna cena (tu: rabat konta 30%; tylko konta z włączonymi zamówieniami) — informacyjnie; w zamówieniu obowiązuje cena z chwili jego złożenia
  "orderStep": 1,                    // ilość = wielokrotność tej liczby (najmniejsze opakowanie)
  "minOrderQuantity": 5,             // najmniejsza ilość do zamówienia (Główki kwiatowe: 5 opakowań; inne kategorie = orderStep)
  "availableStock": 240,             // zamaskowany (przykładowy): maks. 2 × outerCarton; maks. ilość do zamówienia
  "cartonVolume": 0.106,             // objętość kartonu zbiorczego, m³
  "imageUrl": "https://b2b.akces.pl/api/images/A02/A02-003-01.jpg",   // główne zdjęcie = images[0] (adres może mieć parametr ?v=…)
  "images": [                                                       // wszystkie zdjęcia, główne pierwsze
    "https://b2b.akces.pl/api/images/A02/A02-003-01.jpg",
    "https://b2b.akces.pl/api/images/A02/A02-003-02.jpg"
  ],
  "updatedAt": "2026-09-25T14:30:00.000Z"
}

Zamówienia

Pełna instrukcja

Zasady współpracy, bezpieczeństwo, podpis z wektorem testowym, reguły walidacji, statusy, ponawianie i lista kontrolna startu: api.akces.pl/docs/zamowienia.

Dla kont z włączonymi zamówieniami. Zamówienie trafia na konto Twojej firmy (przypisanej do klucza) i jest zawsze zakładane jako odbiór osobisty (Magazyn Akces, ul. Sławęcińska 3, 05-850 Macierzysz), płatne przelewem (termin według warunków Twojego konta), dokument: faktura, ceny netto. Adresu dostawy nie podaje się.

Reguły walidacji

Sprawdzamy wszystkie reguły naraz i zwracamy pełną listę błędów. Jeden błąd odrzuca całe zamówienie — poprawne pozycje nie są zapisywane osobno.

Podpis żądania (HMAC)

Oprócz X-Partner-Key każde żądanie POST (zamówienie i walidacja próbna) wymaga nagłówków:

X-Timestamp: 1790160000                // Unix, sekundy — okno ±300 s
X-Signature: sha256=<hex HMAC-SHA256(sekret, X-Timestamp + "." + ścieżka + "." + surowe_body)>

Sekret podpisu (whsec_…) przekazujemy osobnym kanałem. Ścieżka to /v1/orders albo /v1/orders/validate (podpis walidacji próbnej nie zadziała jako zamówienie). Podpisz dokładnie te bajty, które wysyłasz jako body. Wywołania tylko z serwera — żądania z przeglądarki (z nagłówkiem Origin) są odrzucane (403 BROWSER_NOT_ALLOWED). Wektor testowy do sprawdzenia Twojej implementacji znajdziesz w instrukcji zamówień.

Przykład wywołuje walidację próbną. Żeby złożyć prawdziwe zamówienie, zmień ścieżkę na /v1/orders w podpisie i w adresie — zamówienie trafi na produkcję i zarezerwuje towar.

import crypto from "node:crypto";

const body = JSON.stringify({
  externalOrderNumber: "TEST-0001",
  currency: "PLN",
  notes: "Odbiór we wtorek",
  lines: [{ lineNo: 1, sku: "A02-003", quantity: 12 }],
});
const ts = String(Math.floor(Date.now() / 1000));
const sig = crypto.createHmac("sha256", process.env.AKCES_SIGNING_SECRET)
  .update(ts + "./v1/orders/validate." + body).digest("hex");

const res = await fetch("https://api.akces.pl/v1/orders/validate", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Partner-Key": process.env.AKCES_API_KEY,
    "X-Timestamp": ts,
    "X-Signature": "sha256=" + sig,
  },
  body,
});
const json = await res.json();   // 200 → json.data.valid, json.data.errors, json.data.lines (ceny Akces)
$body = json_encode([
  "externalOrderNumber" => "TEST-0001",
  "currency" => "PLN",
  "lines" => [["lineNo" => 1, "sku" => "A02-003", "quantity" => 12]],
], JSON_UNESCAPED_UNICODE);
$ts = (string) time();
$sig = hash_hmac("sha256", $ts . "./v1/orders/validate." . $body, getenv("AKCES_SIGNING_SECRET"));

$ch = curl_init("https://api.akces.pl/v1/orders/validate");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => $body,          // dokładnie ten sam string, który podpisano
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Content-Type: application/json",
    "X-Partner-Key: " . getenv("AKCES_API_KEY"),
    "X-Timestamp: " . $ts,
    "X-Signature: sha256=" . $sig,
  ],
]);
$result = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
import hashlib, hmac, json, os, time, requests

body = json.dumps({
    "externalOrderNumber": "TEST-0001",
    "currency": "PLN",
    "lines": [{"lineNo": 1, "sku": "A02-003", "quantity": 12}],
}, ensure_ascii=False).encode("utf-8")
ts = str(int(time.time()))
sig = hmac.new(os.environ["AKCES_SIGNING_SECRET"].encode(), ts.encode() + b"./v1/orders/validate." + body, hashlib.sha256).hexdigest()

r = requests.post("https://api.akces.pl/v1/orders/validate", data=body, headers={
    "Content-Type": "application/json",
    "X-Partner-Key": os.environ["AKCES_API_KEY"],
    "X-Timestamp": ts,
    "X-Signature": "sha256=" + sig,
})

Odpowiedzi

{
  "error": "Order rejected. See errors for details.",
  "code": "ORDER_REJECTED",
  "data": {
    "status": "REJECTED",
    "errors": [
      { "code": "INSUFFICIENT_STOCK", "lineNo": 1, "sku": "A02-003",
        "message": "Quantity of A02-003 exceeds the available quantity (availableStock).",
        "details": { "maxOrderable": 240 } },
      { "code": "PACKAGING_MULTIPLE", "lineNo": 2, "sku": "B14-01",
        "message": "Quantity 100 of B14-01 is not a multiple of the packaging unit (96).",
        "details": { "orderStep": 96, "packaging": { "package": null, "innerCarton": 96, "outerCarton": 1152 },
                     "suggestedQuantities": [96, 192] } }
    ],
    …   // odpowiedź skrócona: data zawiera też id, externalOrderNumber, lines, totalNetto, createdAt, updatedAt
  }
}

Kody błędów: UNKNOWN_SKU, EAN_MISMATCH, PRODUCT_NOT_AVAILABLE, DUPLICATE_LINE, PACKAGING_MULTIPLE, BELOW_MINIMUM_QUANTITY (z minOrderQuantity), INSUFFICIENT_STOCK (z maxOrderable), CONTRACTOR_BLOCKED. Pełna tabela kodów HTTP: /docs/zamowienia.

Limity: 10 zamówień/min, 30 walidacji/min, 60 odczytów statusu/min; maks. 500 prób zamówień w ciągu ostatnich 24 h (okno kroczące, przyjęte i odrzucone łącznie); maks. 500 pozycji i 256 KB na zamówienie.

Najczęstsze pytania

Czy pokazujecie prawdziwe stany magazynowe?

Stany są maskowane: wartości poniżej 5 pokazujemy jako 0, a wartości powyżej 2× kartonu zbiorczego (outerCarton) — jako 2× karton zbiorczy. Dla produktów bez zdefiniowanego kartonu zbiorczego stan nie jest ograniczany do 2× karton. Dla kont z zamówieniami availableStock jest dodatkowo zaokrąglany w dół do wielokrotności orderStep (np. 10 przy kroku 6 → 6) i jest to maksymalna ilość, jaką możesz zamówić. Produkty, których nie można zamówić przez API, mają wtedy availableStock 0 i yourPriceNetto null. Dzięki temu widzisz realną dostępność towaru do zamówienia.

Co z błędami i kodami HTTP?

Katalog: 200 OK, 400 niepoprawny parametr zapytania (np. updatedSince w złym formacie), 401 brak klucza albo nieprawidłowy klucz, 403 adres IP spoza listy dozwolonych (FORBIDDEN) albo żądanie przez http:// zamiast https:// (HTTPS_REQUIRED), 404 zasób nie istnieje, 405 niedozwolona metoda HTTP (lista dozwolonych w nagłówku Allow), 429 przekroczony limit żądań (z nagłówkiem Retry-After), 5xx błąd po naszej stronie (503 z nagłówkiem Retry-After).

Zamówienia: 201 przyjęte, 202 czeka na zatwierdzenie, 200 powtórka, 400 błąd schematu, 409 numer użyty z inną treścią, 413 za duże body, 415 brak nagłówka Content-Type: application/json, 422 odrzucone; 403 także ORDERS_DISABLED (konto bez włączonych zamówień), BROWSER_NOT_ALLOWED (żądanie z przeglądarki) i HTTPS_REQUIRED (żądanie przez http://). Pełna tabela: /docs/zamowienia.

Treść odpowiedzi z błędem jest w formacie JSON i zawiera pole code — stały identyfikator błędu do obsługi w Twoim programie.

Jak często mogę odpytywać API?

Limity liczymy na konto, osobno dla każdej grupy: katalog (GET /v1/products i /v1/products/{sku}) — wspólny limit, domyślnie 60 żądań/min; POST /v1/orders — 10/min; POST /v1/orders/validate — 30/min; GET /v1/orders i /v1/orders/{id} — 60/min. Do tego maks. 500 prób zamówień (przyjętych i odrzuconych 422) w oknie kroczącym 24 h oraz maks. 500 pozycji i 256 KB body na zamówienie. Do masowego pobierania używaj listy z limit=200. Jeśli limit katalogu to za mało dla Twoich potrzeb — daj znać, podniesiemy.

Po przekroczeniu dostajesz HTTP 429 (RATE_LIMITED albo DAILY_LIMIT_EXCEEDED) z nagłówkiem Retry-After — odczekaj wskazaną liczbę sekund i ponów (przy DAILY_LIMIT_EXCEEDED ta sama wartość jest w polu retryAfterSeconds). Po 30 nieudanych próbach uwierzytelnienia w ciągu minuty z jednego adresu IP wszystkie żądania z tego adresu dostają 429 do końca tej minuty.

Czy są webhooki (powiadomienia push)?

Na razie nie. Polecamy odpytywanie: zmiany katalogu dociągaj przez updatedSince (pole timestamp z poprzedniej odpowiedzi minus 5 min), a co 15–30 min pobierz pełną listę (limit=200) — Twoja cena (yourPriceNetto) i rezerwacje zmieniają się bez zmiany updatedAt. Statusy zamówień sprawdzaj przez GET /v1/orders?updatedSince=…. Jeśli potrzebujesz powiadomień push do Twojego systemu — zgłoś się, rozważymy to w planach rozwoju.

Co oznaczają statusy realizacji zamówienia?

Dla zamówień ACCEPTED pole fulfillmentStatus pokazuje etap realizacji: NOWE, DO_REALIZACJI, W_REALIZACJI, WSTRZYMANE, DO_ODBIORU, WYSLANE, ODEBRANE, CZESCIOWO_ZREALIZOWANE, ZREALIZOWANE albo ANULOWANE. Nieznaną wartość traktuj jak W_REALIZACJI. Dla zamówień PENDING_REVIEW, REJECTED i DECLINED pole ma wartość null. Szczegóły: /docs/zamowienia.

SDK w moim języku?

Nie udostępniamy gotowych SDK. Wygeneruj klienta z naszej specyfikacji /openapi.json, używając openapi-generator: dostępne są generatory dla Pythona, Javy, JS/TS, PHP, C#, Go, Rusta i wielu innych. Ponieważ w ramach v1 mogą dochodzić nowe pola i wartości, włącz opcje, które je tolerują: --additional-properties=disallowAdditionalPropertiesIfNotPresent=false,enumUnknownDefaultCase=true.

Co, jeśli zgubię klucz?

Napisz na kontakt@akces.pl. Wygenerujemy nowy klucz — stary przestanie działać w chwili przełączenia. Rotację klucza lub sekretu podpisu możesz zlecić planowo: umówimy godzinę przełączenia, a nowe dane przekażemy osobnymi kanałami.

Czy jest środowisko testowe?

Aktualnie dostępne jest tylko produkcyjne API. Odczyt katalogu jest bezpieczny do testowania na żywo — zacznij od ?limit=1. Zamówienia testuj przez POST /v1/orders/validate (te same reguły i ten sam algorytm podpisu ze ścieżką /v1/orders/validate; bez rezerwacji i bez zapisu). Walidacja próbna nie sprawdza, czy externalOrderNumber był już użyty (409 lub powtórka 200), ani limitu prób na 24 h.

Pomoc i kontakt

Pytania, problemy, sugestie?

🛒 Dział obsługi klienta

Zamówienia, zmiany, anulowanie, odbiór, większe ilości.

hurtownia@akces.pl

📧 Wsparcie techniczne API

Błędy integracji, podniesienie limitu, nowy klucz lub sekret podpisu.

kontakt@akces.pl

🌐 Sklep B2B

Katalog w przeglądarce i składanie zamówień dla klientów z kontem B2B (wymaga logowania).

b2b.akces.pl →

Historia zmian

Aktualna wersja kontraktu: 1.5.1.

Stabilny kontrakt v1 — zasady zgodności

W ramach v1 możemy dodawać pola w odpowiedziach, kody błędów i wartości statusów — ignoruj nieznane pola, a nieznaną wartość obsłuż jako przypadek ogólny. Zmiany niezgodne wstecz ogłaszamy mailowo z wyprzedzeniem.