Session from a packshot
Step by step — from uploading a ready packshot to receiving the session images and rating the results.
What you'll achieve
The merchant already has a product packshot — a photo on a clean, neutral background. In this tutorial you'll upload that file, register it as a packshot (it gets approved automatically), order a photo session, and receive the finished images.
Prerequisites
- A plugin installation API key (how to get one) with these permissions:
plugin.assets:upload,plugin.catalog:write,plugin.jobs:create,plugin.jobs:read. - The packshot file (JPEG/PNG/WebP, up to 50 MB).
In the examples, replace mk_live_… with your own key. The base address is https://qamera.ai.
Flow
1. POST /assets/upload → asset_id + a temporary upload URL
2. PUT <upload_url> → send the file
3. POST /packshots → register the packshot (approved immediately)
4. POST /jobs → order a photo session
5. webhook / GET /jobs/{id} → receive the finished images
6. POST /jobs/{id}/accept → (optional) rate the results
Steps
1. Get a temporary URL to upload the file
curl -X POST https://qamera.ai/api/v1/plugin/assets/upload \
-H "X-Api-Key: mk_live_xxxxxxxx.yyyyyyyy" \
-H "Content-Type: application/json" \
-d '{
"mode": "presigned",
"filename": "kubek-packshot.jpg",
"content_type": "image/jpeg",
"size_bytes": 482310
}'
Response (HTTP 201):
{
"asset_id": "9a3b8f4c-2e7a-4c1b-8d0a-1f6c2e9b3d51",
"upload_url": "https://…/sign/…",
"expires_at": "2026-06-03T14:00:00.000Z"
}
Save asset_id — you'll use it in step 3. The upload_url is valid for 2 hours; if it expires, just request a new one.
2. Send the file
curl -X PUT "$UPLOAD_URL" \ --upload-file kubek-packshot.jpg \ -H "Content-Type: image/jpeg"
3. Register the packshot
Packshots you upload yourself are approved automatically — we assume that if you picked them, they're ready to use. If the product with the given product_ref doesn't exist in the catalog yet, provide product_metadata.display_name and it will be created.
curl -X POST https://qamera.ai/api/v1/plugin/packshots \
-H "X-Api-Key: mk_live_xxxxxxxx.yyyyyyyy" \
-H "Content-Type: application/json" \
-d '{
"packshots": [
{
"external_ref": "sklep1:packshot-42",
"product_ref": "sklep1:produkt-7",
"product_metadata": { "display_name": "Kubek ceramiczny 300 ml" },
"asset_id": "9a3b8f4c-2e7a-4c1b-8d0a-1f6c2e9b3d51"
}
]
}'
Response (HTTP 200):
{
"results": [
{
"external_ref": "sklep1:packshot-42",
"product_id": "5e1f8a2c-9b4d-4a3e-8f7c-0d2a6e8b1c34",
"packshot_id": "7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d",
"status": "created"
}
]
}
Remember product_ref (sklep1:produkt-7) — that's how you'll point to the product in step 4. Calling again with the same external_ref returns status: "existing" instead of creating a duplicate.
4. Order a photo session
You don't have to provide packshot_asset_id — when you omit it, the session uses the product's latest approved packshot (the one from step 3). You can pull the configuration (style, scenery, model) from the catalog — see the session parameters tutorial.
curl -X POST https://qamera.ai/api/v1/plugin/jobs \
-H "X-Api-Key: mk_live_xxxxxxxx.yyyyyyyy" \
-H "Idempotency-Key: sklep1-zamowienie-1001" \
-H "Content-Type: application/json" \
-d '{
"session_config": { "aspect_ratio": "4:5" },
"subjects": [
{
"product_label": "Kubek ceramiczny 300 ml",
"product_ref": "sklep1:produkt-7",
"images_count": 4,
"ai_model": "byteplus/seedream-4.5"
}
]
}'
Response (HTTP 201):
{
"order_id": "00000000-0000-0000-0000-000000000099",
"status": "pending",
"subjects": [
{
"product_ref": "sklep1:produkt-7",
"job_ids": [
"00000000-0000-0000-0000-0000000000a1",
"00000000-0000-0000-0000-0000000000a2",
"00000000-0000-0000-0000-0000000000a3",
"00000000-0000-0000-0000-0000000000a4"
]
}
]
}
Save order_id (the whole session) and job_ids (one job per image). The Idempotency-Key header ensures that re-sending the same request (e.g. after a timeout) won't create a second session.
Pull the ai_model value (a provider/model pair) from GET /ai-models — the list depends on the merchant account's plan.
5. Receive the finished images
When a job finishes, we send a webhook to your installation's address — details in the receiving results tutorial. You can also poll:
curl https://qamera.ai/api/v1/plugin/jobs/00000000-0000-0000-0000-0000000000a1 \ -H "X-Api-Key: mk_live_xxxxxxxx.yyyyyyyy"
A finished job has status: "completed" and an outputs[] list with the image download URLs. The URLs are valid for at least 7 days — after that, fetch fresh ones with POST /jobs/{id}/refresh-url.
6. (Optional) Rate the results
You can record the merchant's rating for each image. For a photo session this is pure feedback — it doesn't change credits or anything in the catalog.
curl -X POST https://qamera.ai/api/v1/plugin/jobs/00000000-0000-0000-0000-0000000000a1/accept \ -H "X-Api-Key: mk_live_xxxxxxxx.yyyyyyyy"
Returns 204 No Content. The …/reject endpoint works the same way.
Common errors
| Error | Why it happened | What to do |
|---|---|---|
422 packshot_not_approved | The product with product_ref has no approved packshot (e.g. a typo in product_ref, or the packshot wasn't registered) | Check product_ref; make sure step 3 returned status: "created" or "existing" — details |
402 quota_exceeded | The merchant account doesn't have enough credits for the session | The merchant needs to top up credits; check the account balance with GET /me — details |
409 idempotency_conflict | The same Idempotency-Key used with a different body | Use a new key for a new request — details |
409 job_not_completed | A rating (accept/reject) was sent before the job finished | Wait for status: "completed" — details |
403 forbidden | The key lacks the required permission | Generate a key with the permissions from the "Prerequisites" section — details |
413 on upload | The file is larger than 50 MB | Shrink the file before uploading |
Next steps
- Packshot from a photo — when the merchant has no ready packshot.
- Session parameters — styles, sceneries, and models to choose from.
- Receiving results — webhooks, retries, refreshing URLs.