Python · Virtual try-on API
Virtual try-on API di Python
Ringkasan singkat
Instal requests, muat PHOTTA_API_KEY dari env, tulis wrapper photta() yang mengirimkan Bearer key dan memunculkan PhottaError bertipe pada respons non-2xx, lalu kirim POST ke /api/v1/tryon/apparel dan lakukan polling ke /api/v1/tryon/apparel/{id} setiap 3 detik hingga status bernilai completed.
- Waktu umum: 1.5–4 min
- Credits: 5 credits pada 2K · 6 credits pada 4K
- Pemrosesan: async, polling
- Batasan: 600 requests/min
- Autentikasi: Bearer key
Setiap angka di halaman ini bersumber dari dokumentasi API Photta · diperiksa
RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/tryon/apparel \
-H "Authorization: Bearer $PHOTTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')
# $ID is data.id from the POST response. Poll every 3 seconds until status is "completed" or "failed".
for i in $(seq 1 120); do
RESULT=$(curl -s "https://api.photta.app/api/v1/tryon/apparel/$ID" -H "Authorization: Bearer $PHOTTA_API_KEY")
STATUS=$(echo "$RESULT" | jq -r '.data.status')
[ "$STATUS" = "completed" ] && break
[ "$STATUS" = "failed" ] && echo "generation failed" && exit 1
sleep 3
done
echo "$RESULT" | jq -r '.data.output_url'const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}),
});
const { data } = await res.json(); // data.id, data.status
async function waitFor(id) {
for (let attempt = 0; attempt < 120; attempt++) {
const res = await fetch(`https://api.photta.app/api/v1/tryon/apparel/${id}`, { headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}` } });
const { data } = await res.json();
if (data.status === "completed") return data.output_url;
if (data.status === "failed") throw new Error(data.error_message ?? "generation failed");
await new Promise((r) => setTimeout(r, 3000));
}
throw new Error("timed out after 6 minutes");
}import os, requests
res = requests.post(
"https://api.photta.app/api/v1/tryon/apparel",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": True,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
},
)
data = res.json()["data"] # data["id"], data["status"]
import time
def wait_for(job_id):
for _ in range(120):
res = requests.get(f"https://api.photta.app/api/v1/tryon/apparel/{job_id}", headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"})
data = res.json()["data"]
if data["status"] == "completed":
return data["output_url"]
if data["status"] == "failed":
raise RuntimeError(data.get("error_message", "generation failed"))
time.sleep(3)
raise TimeoutError("timed out after 6 minutes")Sekilas
Sekilas
- Endpoint
- POST /api/v1/tryon/apparel
- Autentikasi
- API key Bearer
- Pemrosesan
- Asinkron — lakukan polling ke endpoint status
- Waktu umum
- 1.5–4 min
- Credits
- 5 credits pada 2K · 6 credits pada 4K
- Rasio aspek
- 3:4 · 1:1 · 4:3 · 9:16 · 16:9
- Batas input
- Hingga 10 MB per gambar; JPEG, PNG, WebP
- Idempoten
- Tidak
Cara kerja
Lima langkah, nol dependensi khusus Photta — requests mencakup segalanya.
Langkah 1
Daftar dan buat key
Jalur yang sama seperti bahasa lainnya: ai.photta.app → Developers → Generate API key. Key dimulai dengan `photta_live_` dan bekerja di seluruh kapabilitas Photta.
Langkah 2
Muat key dari env
Tetapkan `PHOTTA_API_KEY` di environment dan baca via `os.environ`. Di FastAPI atau Django, muat sekali saat booting ke dalam modul settings. Jangan sematkan key di kode sumber atau riwayat Git publik.
python3 -m pip install requests export PHOTTA_API_KEY="photta_live_xxxxx"Langkah 3
Tulis wrapper requests
Fungsi `photta_request()` sebanyak 30 baris menangani base URL, header Authorization, serialisasi JSON, dan translasi error. Hanya itu abstraksi yang Anda butuhkan sampai Python SDK dirilis.
# photta.py — one helper for every endpoint import os, requests BASE = "https://api.photta.app/api/v1" class PhottaError(Exception): def __init__(self, status, error, retry_after=None): super().__init__(error.get("message", "request failed")) self.status, self.type, self.retry_after = status, error.get("type"), retry_after def photta(method, path, **kwargs): res = requests.request(method, BASE + path, headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"}, timeout=30, **kwargs) body = res.json() if not res.ok: raise PhottaError(res.status_code, body.get("error", {}), res.headers.get("Retry-After")) return bodyLangkah 4
Kirim dan lakukan polling
Lakukan POST ke `/api/v1/tryon/apparel` untuk mendapatkan ID pembuatan, lalu lakukan polling ke `/api/v1/tryon/apparel/{id}` dengan interval 3 detik. Di Celery atau RQ, bagi loop polling ke beberapa task agar pekerjaan yang memakan waktu beberapa menit tidak membebani worker.
import os, requests res = requests.post( "https://api.photta.app/api/v1/tryon/apparel", headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"}, json={ "product_type": "top", "product_images": [ "https://cdn.yourstore.com/products/shirt-front.jpg" ], "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg", "product_category": "t_shirt", "mannequin_id": "mnk_f3a9b1", "pose_id": "pose_c2d4e5", "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg", "lock_background": True, "resolution": "2K", "aspect_ratio": "3:4", "body_size": "M", "expression": "neutral", "user_instruction": "Keep the collar pattern crisp and centered." }, ) data = res.json()["data"] # data["id"], data["status"] import time def wait_for(job_id): for _ in range(120): res = requests.get(f"https://api.photta.app/api/v1/tryon/apparel/{job_id}", headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"}) data = res.json()["data"] if data["status"] == "completed": return data["output_url"] if data["status"] == "failed": raise RuntimeError(data.get("error_message", "generation failed")) time.sleep(3) raise TimeoutError("timed out after 6 minutes")Langkah 5
Simpan hasilnya secara permanen
Payload completed mencakup `output_url` dan `thumbnail_url`. Unduh byte-nya ke object storage Anda sendiri — S3, GCS, Cloudflare R2 — agar produk Anda tidak terikat dengan CDN Photta untuk rendering jangka panjang.
Error
- 400
invalid_request_error - The request is malformed or contains invalid parameters.
- 401
authentication_error - The API key is missing, invalid, or expired.
- 402
insufficient_credits_error - Your account does not have enough credits.
- 404
not_found_error - The requested resource does not exist.
- 409
conflict_error - The request conflicts with current state — e.g. your concurrent-batch cap is reached.
- 429
rate_limit_error - Too many requests. Slow down and retry.Retry-After: 30
- 500
api_error - An internal server error occurred. Retry later.
try:
photta("POST", "/tryon/apparel", json={
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": True,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
})
except PhottaError as e:
if e.status == 402:
print("insufficient_credits_error: top up before retrying")
elif e.status == 429:
time.sleep(int(e.retry_after or 30))
else:
raiseBatasan
- 600 request per menit per API key (Fixed window; batasannya sama di setiap paket)
- Respons 429 menyertakan Retry-After: 30 detik
- Hingga 10 MB per gambar
- Format: JPEG, PNG, WebP
- Batch konkuren per paket: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
- Hanya polling — API tidak mengirim webhook.
Alasan requests adalah pilihan yang tepat saat ini
- Tanpa dependensi khusus Photta — requests sudah ada di sebagian besar proyek Python
- Bisa berjalan di mana pun Python berjalan: Django, FastAPI, Flask, worker Celery, Lambda, skrip
- Wrapper klien-nya hanya sekitar 30 baris — tempelkan ke photta.py dan lanjutkan pekerjaan Anda
- Cocok dipadukan dengan asyncio via httpx jika Anda membutuhkan pengiriman paralel
Hal yang tidak dilakukannya
- Belum ada package Python resmi untuk Photta — REST dengan requests adalah pola yang terdokumentasi
- Polling adalah satu-satunya sinyal penyelesaian; API ini tidak mengirim webhook
- Hanya menggunakan Bearer key; tidak ada alur client-credentials OAuth
Pertanyaan umum developer
Apakah ada SDK Python resmi untuk Photta?
Belum ada. Jalur integrasi yang didukung adalah library requests (sinkron) atau httpx (asinkron) — keduanya hanya membutuhkan wrapper tipis, dan wrapper di halaman ini berfungsi untuk setiap kapabilitas.
Versi Python mana saja yang didukung?
Python 3.9 dan yang lebih baru. Wrapper ini menggunakan type hints, f-strings, dan sintaks `str | None`, yang berjalan lancar di 3.10+. Pada 3.9, ubah `str | None` menjadi `Optional[str]`. requests sendiri secara resmi mendukung 3.8+, tetapi 3.9+ adalah batas minimum praktis untuk proyek Photta modern.
Sebaiknya saya menggunakan requests atau httpx?
Gunakan requests jika Anda hanya membuat beberapa panggilan berurutan — lebih sederhana dan sudah ada di sebagian besar codebase. Gunakan httpx jika Anda membutuhkan konkurensi asinkron (pengiriman paralel, backfill massal) atau HTTP/2. Bagaimanapun, wrapper-nya sangat ringkas; cukup ganti `requests.request` dengan `httpx.Client().request` dan sisa kodenya tetap identik.
Bisakah saya memanggilnya dari Django?
Bisa. Tempatkan wrapper di `services/photta.py`, lalu impor dari sebuah view atau task Celery. Jangan memanggil API di dalam request handler sinkron jika pekerjaannya membutuhkan waktu lama — kirim dari view, kembalikan ID pembuatan, lalu lakukan polling dari task latar belakang atau Channels consumer.
Bagaimana cara melakukan polling dari worker Celery?
Kirim pekerjaan dari satu task, lalu jadwalkan task lanjutan (melalui `apply_async(countdown=3)`) yang melakukan polling sekali dan menjadwalkan ulang dirinya sendiri hingga pekerjaan selesai atau mencapai batas maksimum percobaan ulang. Ini menjaga worker tetap bebas dan menghindari task yang berjalan terlalu lama yang dapat mengganggu autoscaler.
Bagaimana API memberikan sinyal error?
Respons non-2xx menyertakan body JSON dengan objek `error`: `type`, `code`, `message`, ditambah `param` pada 400 dan `retry_after` pada 429. Wrapper di halaman ini memicu `PhottaError` yang membawa semua informasi ini sehingga pemanggil Anda dapat membuat percabangan logika berdasarkan status code tanpa perlu mem-parsing body sendiri.
Halaman terkait
Node.js
Virtual try-on API di Node.js
Panggil virtual try-on API Photta dari backend Node.js dengan fetch native. Tidak memerlukan SDK: simpan kunci Anda, kirim job, lakukan polling untuk hasilnya.
BacacURL
Virtual try-on API dengan cURL
Panggil virtual try-on API Photta langsung dari shell menggunakan cURL. Kirim, lakukan polling, unduh — setiap cuplikan kode dapat dipadukan dengan jq untuk pipeline berbasis skrip.
BacaKapabilitas
Virtual try-on API untuk pakaian
REST API yang memakaikan pakaian pada manekin AI. Asinkron, waktu generasi 1.5–4 menit, 5 credits pada 2K, 6 pada 4K. Contoh cURL, Node.js, dan Python.
BacaBangun
Bangun fitur virtual try-on untuk aplikasi Anda
Resep end-to-end untuk merilis fitur virtual try-on dengan Photta API: unggah, submit, lakukan polling dari worker, render hasilnya. Pola TypeScript + server-only.
BacaBangun
Tambahkan virtual try-on ke aplikasi iOS atau Android
Cara menambahkan AI virtual try-on ke aplikasi native iOS atau Android menggunakan Photta API: jangan pernah menyertakan key ke perangkat, lakukan proxy melalui backend Anda, mirror status job.
BacaQuickstart
Gambar Photta pertama dalam waktu kurang dari lima menit.
Daftar, buat API key, jalankan pemanggilan cURL pertama Anda, lakukan polling hingga selesai, simpan hasilnya. Lima langkah, terdokumentasi end-to-end.
BacaReferensi
Harga Photta API
Biaya setiap endpoint Photta API dalam credits pada 2K dan 4K, cara kerja pemotongan dan pengembalian dana, serta endpoint mana saja yang gratis. Tidak ada harga uang per gambar.
Baca
Setiap angka di halaman ini bersumber dari dokumentasi API Photta · diperiksa
Coba API dalam lima menit
Buat Photta API key, tempel cuplikan cURL di atas, dan Anda akan mendapatkan gambar on-model pertama sebelum kopi selesai diseduh.
- 1.5–4 min
- 5 credits pada 2K · 6 credits pada 4K
- async, polling
- 600 requests/min
- Bearer key