Przykłady
Kompletne przykłady integracji z użyciem curl, JavaScript i Python.
Ta strona przedstawia kompletny przepływ pracy generowania sesji zdjęciowej w trzech językach: curl, JavaScript (fetch) i Python (requests). Każdy przykład realizuje te same kroki:
- Wylistuj produkty, aby wybrać jeden do sesji.
- Wylistuj zatwierdzone modele AI i scenerie.
- Zarejestruj generowanie sesji zdjęciowej, łącząc produkt, model i scenerię.
- Odpytuj endpoint image-picker, aż wyniki będą gotowe.
- Przejrzyj i zatwierdź wygenerowane zdjęcia.
Wspólna konfiguracja
Każde zapytanie wymaga dwóch rzeczy:
- Bazowy URL —
https://app.qamera.ai(zastąp własnym URL w przypadku wdrożeń self-hosted). - Uwierzytelnianie — Przekaż API key w nagłówku
X-Api-Key.
X-Api-Key: mk_live_abc123.secret456
API key możesz wygenerować w Ustawienia > API Keys w zespołowym workspace. Klucz jest wyświetlany tylko raz, więc skopiuj go natychmiast.
Endpointy GET są bezpłatne i nigdy nie zużywają kredytów. Endpointy POST uruchamiające generowanie treści rezerwują kredyty z góry i zużywają je po zakończeniu przetwarzania.
Przykłady curl
Krok 1 — Lista produktów
Pobierz wszystkie produkty przesłane na Twoje konto.
curl -s -X GET "https://app.qamera.ai/api/external/products" \ -H "X-Api-Key: mk_live_abc123.secret456"
Odpowiedź:
{
"products": [
{
"id": "rec_product_001",
"name": "White T-Shirt Front",
"thumbnail": "https://cdn.example.com/products/thumb_001.jpg",
"status": "UPLOADED",
"createdAt": "2026-03-20T14:30:00.000Z"
},
{
"id": "rec_product_002",
"name": "Leather Handbag",
"thumbnail": "https://cdn.example.com/products/thumb_002.jpg",
"status": "UPLOADED",
"createdAt": "2026-03-21T09:15:00.000Z"
}
],
"count": 2
}
Wybierz ID produktu do użycia w sesji zdjęciowej. W tych przykładach użyjemy rec_product_001.
Krok 2 — Lista zatwierdzonych modeli
Pobierz tylko modele, które zostały zatwierdzone do użycia.
curl -s -X GET "https://app.qamera.ai/api/external/models?statusFilter=approved" \ -H "X-Api-Key: mk_live_abc123.secret456"
Odpowiedź:
{
"models": [
{
"id": "rec_model_101",
"name": "Sophie — Casual",
"thumbnail": "https://cdn.example.com/models/thumb_101.jpg",
"status": "DONE",
"voting": "APPROVED",
"createdAt": "2026-03-18T10:00:00.000Z"
}
],
"count": 1
}
Krok 3 — Lista zatwierdzonych scenerii
curl -s -X GET "https://app.qamera.ai/api/external/sceneries?statusFilter=approved" \ -H "X-Api-Key: mk_live_abc123.secret456"
Odpowiedź:
{
"sceneries": [
{
"id": "rec_scenery_201",
"name": "Bright Studio",
"thumbnail": "https://cdn.example.com/sceneries/thumb_201.jpg",
"status": "DONE",
"voting": "APPROVED",
"createdAt": "2026-03-19T11:45:00.000Z"
}
],
"count": 1
}
Krok 4 — Rejestracja sesji zdjęciowej
Połącz produkt, model i scenerię, aby rozpocząć generowanie. Ten endpoint rezerwuje kredyty.
curl -s -X POST "https://app.qamera.ai/api/external/image-picker/register-ideas" \
-H "X-Api-Key: mk_live_abc123.secret456" \
-H "Content-Type: application/json" \
-d '{
"config": {
"product": { "id": "rec_product_001" },
"model": { "id": "rec_model_101" },
"scenery": { "id": "rec_scenery_201" },
"industry": "fashion",
"suggestions": "bright lighting, clean composition"
},
"count": 4
}'
Odpowiedź:
{
"createdRecordIds": ["rec_gen_301", "rec_gen_302", "rec_gen_303", "rec_gen_304"],
"batchId": "batch_abc123",
"orderId": "ord_xyz789",
"reservationId": "res_def456",
"creditsReserved": 120
}
Zapisz createdRecordIds — użyjesz ich do sprawdzania postępu.
Krok 5 — Odpytywanie o wyniki
Generowanie jest asynchroniczne. Odpytuj endpoint image-picker, filtrując po produkcie, aż zdjęcia osiągną status DONE.
curl -s -X GET "https://app.qamera.ai/api/external/image-picker?productId=rec_product_001" \ -H "X-Api-Key: mk_live_abc123.secret456"
Odpowiedź (w trakcie przetwarzania):
{
"images": [
{
"id": "rec_gen_301",
"name": "White T-Shirt — Variant 1",
"thumbnail": "",
"status": "INPROGRESS",
"voting": null,
"createdAt": "2026-03-27T12:00:00.000Z"
}
],
"count": 1
}
Odczekaj minutę i wywołaj ten sam endpoint ponownie. Gdy status zmieni się na DONE, pole thumbnail będzie zawierało URL zdjęcia.
Krok 6 — Zatwierdzanie lub odrzucanie wyników
Możesz zatwierdzać zdjęcia za pomocą endpointu aktualizacji packshotu. Zdjęcia z sesji, które chcesz zachować, zatwierdź, aby pojawiały się w filtrowanych widokach.
# Zatwierdź zdjęcie
curl -s -X POST "https://app.qamera.ai/api/external/packshots/update-packshot" \
-H "X-Api-Key: mk_live_abc123.secret456" \
-H "Content-Type: application/json" \
-d '{
"recordId": "rec_gen_301",
"Voting": "APPROVED"
}'
Odpowiedź:
{
"success": true,
"message": "Packshot voting updated successfully",
"recordId": "rec_gen_301"
}
Aby odrzucić zdjęcie (co je archiwizuje):
curl -s -X POST "https://app.qamera.ai/api/external/packshots/update-packshot" \
-H "X-Api-Key: mk_live_abc123.secret456" \
-H "Content-Type: application/json" \
-d '{
"recordId": "rec_gen_302",
"Voting": "REJECTED"
}'
Przykład JavaScript (fetch)
Poniższy przykład wykorzystuje API fetch dostępne w przeglądarce/Node.js do realizacji tego samego przepływu pracy.
Funkcja pomocnicza
const BASE_URL = "https://app.qamera.ai";
const API_KEY = "mk_live_abc123.secret456";
async function qameraFetch(path, options = {}) {
const url = new URL(path, BASE_URL);
if (options.params) {
Object.entries(options.params).forEach(([key, value]) =>
url.searchParams.set(key, value)
);
}
const response = await fetch(url.toString(), {
method: options.method || "GET",
headers: {
"X-Api-Key": API_KEY,
...(options.body ? { "Content-Type": "application/json" } : {}),
},
...(options.body ? { body: JSON.stringify(options.body) } : {}),
});
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(
`API error ${response.status}: ${error.error || response.statusText}`
);
}
return response.json();
}
Pełny przepływ pracy
async function runPhotoShootWorkflow() {
// 1. Lista produktów
const { products } = await qameraFetch("/api/external/products");
console.log(`Found ${products.length} products`);
const product = products[0];
if (!product) throw new Error("No products found. Upload one first.");
console.log(`Using product: ${product.name} (${product.id})`);
// 2. Lista zatwierdzonych modeli
const { models } = await qameraFetch("/api/external/models", {
params: { statusFilter: "approved" },
});
console.log(`Found ${models.length} approved models`);
// 3. Lista zatwierdzonych scenerii
const { sceneries } = await qameraFetch("/api/external/sceneries", {
params: { statusFilter: "approved" },
});
console.log(`Found ${sceneries.length} approved sceneries`);
// 4. Rejestracja generowania sesji zdjęciowej
const registration = await qameraFetch(
"/api/external/image-picker/register-ideas",
{
method: "POST",
body: {
config: {
product: { id: product.id },
model: models[0] ? { id: models[0].id } : undefined,
scenery: sceneries[0] ? { id: sceneries[0].id } : undefined,
industry: "fashion",
suggestions: "bright lighting, clean composition",
},
count: 4,
},
}
);
console.log(`Generation started — order ${registration.orderId}`);
console.log(`Credits reserved: ${registration.creditsReserved}`);
// 5. Odpytywanie aż wyniki będą gotowe
const generatedIds = new Set(registration.createdRecordIds);
let attempts = 0;
const maxAttempts = 30;
while (attempts < maxAttempts) {
await new Promise((resolve) => setTimeout(resolve, 10_000));
attempts++;
const { images } = await qameraFetch("/api/external/image-picker", {
params: { productId: product.id },
});
const ours = images.filter((img) => generatedIds.has(img.id));
const done = ours.filter((img) => img.status === "DONE");
console.log(`Poll ${attempts}: ${done.length}/${ours.length} done`);
if (done.length === ours.length && done.length > 0) {
console.log("All images ready!");
// 6. Zatwierdzenie pierwszego wyniku
await qameraFetch("/api/external/packshots/update-packshot", {
method: "POST",
body: {
recordId: done[0].id,
Voting: "APPROVED",
},
});
console.log(`Approved image ${done[0].id}`);
return done;
}
}
throw new Error("Generation timed out after 5 minutes");
}
runPhotoShootWorkflow()
.then((images) => console.log("Completed:", images))
.catch((err) => console.error("Failed:", err.message));
Przykład Python (requests)
Poniższy przykład wykorzystuje bibliotekę requests (pip install requests).
Konfiguracja sesji
import time
import requests
BASE_URL = "https://app.qamera.ai"
API_KEY = "mk_live_abc123.secret456"
session = requests.Session()
session.headers.update({"X-Api-Key": API_KEY})
Pełny przepływ pracy
def run_photo_shoot_workflow():
# 1. Lista produktów
resp = session.get(f"{BASE_URL}/api/external/products")
resp.raise_for_status()
products = resp.json()["products"]
print(f"Found {len(products)} products")
if not products:
raise RuntimeError("No products found. Upload one first.")
product = products[0]
print(f"Using product: {product['name']} ({product['id']})")
# 2. Lista zatwierdzonych modeli
resp = session.get(
f"{BASE_URL}/api/external/models",
params={"statusFilter": "approved"},
)
resp.raise_for_status()
models = resp.json()["models"]
print(f"Found {len(models)} approved models")
# 3. Lista zatwierdzonych scenerii
resp = session.get(
f"{BASE_URL}/api/external/sceneries",
params={"statusFilter": "approved"},
)
resp.raise_for_status()
sceneries = resp.json()["sceneries"]
print(f"Found {len(sceneries)} approved sceneries")
# 4. Rejestracja generowania sesji zdjęciowej
config = {
"product": {"id": product["id"]},
"industry": "fashion",
"suggestions": "bright lighting, clean composition",
}
if models:
config["model"] = {"id": models[0]["id"]}
if sceneries:
config["scenery"] = {"id": sceneries[0]["id"]}
resp = session.post(
f"{BASE_URL}/api/external/image-picker/register-ideas",
json={"config": config, "count": 4},
)
resp.raise_for_status()
registration = resp.json()
print(f"Generation started — order {registration['orderId']}")
print(f"Credits reserved: {registration['creditsReserved']}")
# 5. Odpytywanie aż wyniki będą gotowe
generated_ids = set(registration["createdRecordIds"])
max_attempts = 30
for attempt in range(1, max_attempts + 1):
time.sleep(10)
resp = session.get(
f"{BASE_URL}/api/external/image-picker",
params={"productId": product["id"]},
)
resp.raise_for_status()
images = resp.json()["images"]
ours = [img for img in images if img["id"] in generated_ids]
done = [img for img in ours if img["status"] == "DONE"]
print(f"Poll {attempt}: {len(done)}/{len(ours)} done")
if len(done) == len(ours) and done:
print("All images ready!")
# 6. Zatwierdzenie pierwszego wyniku
resp = session.post(
f"{BASE_URL}/api/external/packshots/update-packshot",
json={
"recordId": done[0]["id"],
"Voting": "APPROVED",
},
)
resp.raise_for_status()
print(f"Approved image {done[0]['id']}")
return done
raise TimeoutError("Generation timed out after 5 minutes")
if __name__ == "__main__":
try:
results = run_photo_shoot_workflow()
for img in results:
print(f" {img['name']}: {img['thumbnail']}")
except Exception as e:
print(f"Error: {e}")