Przykłady kodu
Gotowe przykłady integracji z API zewnętrznym AMPER w curl, Pythonie, C#, Node.js i PHP: logowanie, pobieranie stronami, limit zapytań, wycena koszyka.
Ostatnia aktualizacja: 26 października 2026
Przykłady pokazują cały przebieg integracji: logowanie, pobranie listy stronami z ponowieniem po odpowiedzi 429 i wycenę koszyka w trybie playground. W przykładach zastąp {amper_ws}, {api_key}, login, hasło i ID klienta swoimi danymi.
Zasady, na których opierają się przykłady: Uwierzytelnianie w API zewnętrznym, Stronicowanie, limity i kody odpowiedzi, Tworzenie zamówienia „create-order”.
curl
Odczyt z kluczem API:
curl "https://{amper_ws}/external/v1/products/?api_key={api_key}&limit=500&offset=0&ordering=id"
Logowanie integratora i odczyt z tokenem:
curl -X POST https://{amper_ws}/external/v1/auth/ \
-H "Content-Type: application/json" \
-d '{"username": "login", "password": "haslo"}'
curl "https://{amper_ws}/external/v1/promotions/?limit=50&offset=0" \
-H "Authorization: Bearer <access_token>"
Wycena koszyka:
curl -X POST https://{amper_ws}/external/v1/create-order \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"customer_id": 42, "playground": true, "lines": [{"product_id": 101, "quantity": 12, "suggested_price": null}]}'
Python
Klient z biblioteką requests: loguje się, odświeża token przed wygaśnięciem i po odpowiedzi 401, czeka po odpowiedzi 429, ponawia odczyt po błędzie serwera (zamówień nie ponawia) i pobiera listy stronami. Działa też z samym kluczem API.
import time
import requests
class AmperExternalApi:
"""API zewnętrzne AMPER: logowanie, odświeżanie tokena, stronicowanie i ponawianie po 429."""
def __init__(self, host, username=None, password=None, api_key=None, timeout=120):
self.base_url = f"https://{host}/external/v1"
self.username = username
self.password = password
self.api_key = api_key
self.timeout = timeout
self.session = requests.Session()
self.access_token = None
self.refresh_token = None
self.expires_at = 0
def _save_tokens(self, data):
self.access_token = data["access_token"]
self.refresh_token = data["refresh_token"]
self.expires_at = time.time() + data["expires_in"] - 30 # 30 s zapasu
def login(self):
response = self.session.post(f"{self.base_url}/auth/", timeout=self.timeout,
json={"username": self.username, "password": self.password})
response.raise_for_status()
self._save_tokens(response.json())
def refresh(self):
response = self.session.post(f"{self.base_url}/auth/refresh/", timeout=self.timeout,
json={"refresh_token": self.refresh_token})
if response.status_code == 400: # refresh_token wygasł – logujemy się ponownie
self.login()
return
response.raise_for_status()
self._save_tokens(response.json())
def _credentials(self):
"""(nagłówki, parametry adresu) z danymi dostępu."""
if self.api_key:
return {}, {"api_key": self.api_key}
if not self.access_token:
self.login()
elif time.time() >= self.expires_at:
self.refresh()
return {"Authorization": f"Bearer {self.access_token}"}, {}
def request(self, method, path, params=None, json=None):
refreshed = False
for attempt in range(5):
headers, auth_params = self._credentials()
response = self.session.request(method, f"{self.base_url}/{path}", headers=headers,
params={**(params or {}), **auth_params}, json=json,
timeout=self.timeout)
if response.status_code == 429: # limit zapytań – czekamy i ponawiamy
time.sleep(int(response.headers.get("Retry-After", 1)))
continue
if response.status_code == 401 and not self.api_key and not refreshed:
self.expires_at = 0 # token wygasł – odświeżamy i ponawiamy raz
refreshed = True
continue
if response.status_code >= 500 and method == "GET": # zamówień nie ponawiamy
time.sleep(2 ** attempt)
continue
break
response.raise_for_status()
return response.json()
def get_all(self, path, page_size=500, **params):
"""Cała lista, strona po stronie."""
items, offset = [], 0
while True:
page = self.request("GET", path, params={**params, "limit": page_size, "offset": offset})
items.extend(page["results"])
if not page["next"]:
return items
offset += page_size
Użycie:
api = AmperExternalApi("{amper_ws}", username="login", password="haslo")
# tylko odczyt: AmperExternalApi("{amper_ws}", api_key="{api_key}")
categories = api.get_all("categories/")
products = api.get_all("products/", ordering="id")
stocks = api.get_all("stocks/")
promotions = api.get_all("promotions/", page_size=50)
lines = [{"product_id": 101, "quantity": 12, "suggested_price": None}]
quote = api.request("POST", "create-order", json={"customer_id": 42, "playground": True, "lines": lines})
for line in quote["lines"]:
print(line["product_id"], line["quantity"], line["given_price"] or line["customer_price"])
order = api.request("POST", "create-order", json={"customer_id": 42, "lines": lines})
if not order["order_id"]:
raise RuntimeError("Zamówienie nie zostało utworzone")
C#
.NET 6 i nowsze, bez dodatkowych bibliotek. Treść żądań to StringContent – wysyła nagłówek Content-Length.
using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
var baseUrl = "https://{amper_ws}/external/v1";
using var client = new HttpClient { Timeout = TimeSpan.FromMinutes(2) };
// Treść JSON (z nagłówkiem Content-Length)
StringContent Json(object body) =>
new(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
// Zapytanie z ponowieniem po 429 (limit 3 jednoczesnych zapytań)
async Task<JsonElement> Send(Func<HttpRequestMessage> request)
{
for (var attempt = 0; attempt < 5; attempt++)
{
using var response = await client.SendAsync(request());
if (response.StatusCode == HttpStatusCode.TooManyRequests)
{
await Task.Delay(response.Headers.RetryAfter?.Delta ?? TimeSpan.FromSeconds(1));
continue;
}
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<JsonElement>();
}
throw new HttpRequestException("Przekroczony limit zapytań");
}
// Logowanie integratora
var token = await Send(() => new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/auth/")
{
Content = Json(new { username = "login", password = "haslo" })
});
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token.GetProperty("access_token").GetString());
// Cała lista produktów, strona po stronie
var products = new List<JsonElement>();
for (var offset = 0; ; offset += 500)
{
var page = await Send(() => new HttpRequestMessage(HttpMethod.Get,
$"{baseUrl}/products/?limit=500&offset={offset}&ordering=id"));
products.AddRange(page.GetProperty("results").EnumerateArray());
if (page.GetProperty("next").ValueKind == JsonValueKind.Null) break;
}
Console.WriteLine($"Produkty: {products.Count}");
// Wycena koszyka (playground)
var quote = await Send(() => new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/create-order")
{
Content = Json(new
{
customer_id = 42,
playground = true,
lines = new[] { new { product_id = 101, quantity = 12m, suggested_price = (decimal?)null } }
})
});
foreach (var line in quote.GetProperty("lines").EnumerateArray())
Console.WriteLine($"{line.GetProperty("product_id")} {line.GetProperty("customer_price")}");
Translatory ERP mogą zamiast tego korzystać z biblioteki AmperApiClient.NET.
Node.js
Node.js 18 i nowsze (wbudowany fetch), moduł ES (.mjs).
const BASE_URL = 'https://{amper_ws}/external/v1';
const sleep = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds * 1000));
// Logowanie integratora: zwraca access_token
async function login(username, password) {
const response = await fetch(`${BASE_URL}/auth/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
if (!response.ok) throw new Error(`Logowanie: HTTP ${response.status}`);
return (await response.json()).access_token;
}
// Zapytanie z ponowieniem po 429
async function call(path, token, options = {}) {
for (let attempt = 0; attempt < 5; attempt++) {
const response = await fetch(`${BASE_URL}/${path}`, {
...options,
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, ...options.headers },
});
if (response.status === 429) {
await sleep(Number(response.headers.get('Retry-After') ?? 1));
continue;
}
if (!response.ok) throw new Error(`${path}: HTTP ${response.status}`);
return response.json();
}
throw new Error(`${path}: przekroczony limit zapytań`);
}
// Cała lista, strona po stronie
async function getAll(path, token, pageSize = 500, query = '') {
const items = [];
for (let offset = 0; ; offset += pageSize) {
const page = await call(`${path}?limit=${pageSize}&offset=${offset}${query}`, token);
items.push(...page.results);
if (!page.next) return items;
}
}
const token = await login('login', 'haslo');
const products = await getAll('products/', token, 500, '&ordering=id');
console.log(`Produkty: ${products.length}`);
const quote = await call('create-order', token, {
method: 'POST',
body: JSON.stringify({
customer_id: 42,
playground: true,
lines: [{ product_id: 101, quantity: 12, suggested_price: null }],
}),
});
for (const line of quote.lines) {
console.log(line.product_id, line.quantity, line.given_price || line.customer_price);
}
PHP
PHP 8 z rozszerzeniem cURL.
<?php
const BASE_URL = 'https://{amper_ws}/external/v1';
function amper(string $method, string $path, ?string $token = null, ?array $body = null): array
{
for ($attempt = 0; $attempt < 5; $attempt++) {
$curl = curl_init(BASE_URL . '/' . $path);
$headers = ['Content-Type: application/json'];
if ($token !== null) {
$headers[] = 'Authorization: Bearer ' . $token;
}
curl_setopt_array($curl, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
]);
if ($body !== null) {
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($body));
}
$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
if ($status === 429) { // limit zapytań – czekamy i ponawiamy
sleep(1);
continue;
}
if ($response === false || $status >= 400) {
throw new RuntimeException("$method $path: HTTP $status");
}
return json_decode($response, true);
}
throw new RuntimeException("$method $path: przekroczony limit zapytań");
}
// Logowanie integratora
$token = amper('POST', 'auth/', null, ['username' => 'login', 'password' => 'haslo'])['access_token'];
// Cała lista produktów, strona po stronie
$products = [];
for ($offset = 0; ; $offset += 500) {
$page = amper('GET', "products/?limit=500&offset=$offset&ordering=id", $token);
$products = array_merge($products, $page['results']);
if ($page['next'] === null) {
break;
}
}
echo 'Produkty: ', count($products), PHP_EOL;
// Wycena koszyka (playground)
$quote = amper('POST', 'create-order', $token, [
'customer_id' => 42,
'playground' => true,
'lines' => [['product_id' => 101, 'quantity' => 12, 'suggested_price' => null]],
]);
foreach ($quote['lines'] as $line) {
echo $line['product_id'], ' ', $line['given_price'] ?: $line['customer_price'], PHP_EOL;
}
Potrzebujesz pomocy? Napisz na support@ampliapps.com albo zadzwoń: +48 85 6000 263.