docs
Everything the app does, you can do with a key.
The public API mirrors the web app one-to-one: declare uploads, PUT straight to storage, analyse, estimate, dry-run, process and export. This page is the shape of it; every endpoint, with its request shape, is in the full API reference, the OpenAPI UI the API serves.
- Concepts
- Recipes
- Credits
- Dry runs
- Smart sampling
- Exports
- API keys
- Connecting a Magento store
API=https://jeani.ai/v1; KEY=pia_live_…
# a key goes in X-API-Key (Bearer is for app sessions); every POST body is JSON
J="-H X-API-Key:$KEY -H Content-Type:application/json"
# 1. workspace, then a project. stripRootFolder is off by default, so paths are stored exactly as
# sent; on, it drops the first folder (products/football/red.jpg is stored as football/red.jpg)
WS=$(curl -s $J $API/workspaces | jq -r '.[0].id')
PRJ=$(curl -s $J $API/workspaces/$WS/projects \
-d '{"name":"Autumn catalogue","stripRootFolder":false}' | jq -r .id)
# 2. declare, PUT straight to storage, complete; completion queues the free analysis
DECL=$(curl -s $J $API/projects/$PRJ/uploads \
-d '{"files":[{"relativePath":"products/football/red.jpg","size":812345,"mimeType":"image/jpeg"}]}')
curl -s -X PUT "$(echo "$DECL" | jq -r '.files[0].upload.url')" \
-H "Content-Type: image/jpeg" --data-binary @red.jpg
curl -s $J $API/uploads/$(echo "$DECL" | jq -r .session.id)/complete \
-d "$(echo "$DECL" | jq -c '{files:[.files[]|{assetId}]}')"
until curl -s $J $API/projects/$PRJ | jq -e .analysedAt >/dev/null; do sleep 5; done
# 3. the estimate is what a run will cost; it is the only call that quotes credits
curl -s $J $API/recipes/rcp_sys_amazon_white/estimate \
-d "{\"projectId\":\"$PRJ\"}" | jq '{expected,worstCase,unanalysed}'
# 4. the dry run is free: up to ten images through the recipe, inspected, 0 credits, no quote
DRY=$(curl -s $J $API/jobs -H "Idempotency-Key: dry-1" \
-d "{\"projectId\":\"$PRJ\",\"type\":\"DRY_RUN\",\"recipeId\":\"rcp_sys_amazon_white\"}" | jq -r .id)
until curl -s $J $API/jobs/$DRY | jq -r .status | grep -Eqv 'QUEUED|RUNNING'; do sleep 5; done
curl -s $J $API/jobs/$DRY | jq '.progress | {passed,needsReview,failed}'
curl -s $J "$API/projects/$PRJ/assets?sort=qa" | jq '.data[] | {relativePath,status,qaOverall}'
# 5. the real run, then the replacement-ready ZIP
JOB=$(curl -s $J $API/jobs -H "Idempotency-Key: run-1" \
-d "{\"projectId\":\"$PRJ\",\"type\":\"PROCESS\",\"recipeId\":\"rcp_sys_amazon_white\"}" | jq -r .id)
until curl -s $J $API/jobs/$JOB | jq -r .status | grep -Eqv 'QUEUED|RUNNING'; do sleep 5; done
EXP=$(curl -s $J $API/projects/$PRJ/exports -d '{"mode":"REPLACEMENT"}' | jq -r .id)
until curl -s $J $API/exports/$EXP | jq -r .status | grep -q READY; do sleep 5; done
curl -sL "$(curl -s $J $API/exports/$EXP/download | jq -r .url)" -o catalogue.zip