vanillaxbox
HomePricingAPI docsHelp centreContact usLegal
Language
Sign inOpen app
HomePricingAPI docsHelp centreContact usLegal
© 2026 VanillaX Inc. · VanillaX Box
Language
vanillax.co
API v1OpenAPI 3.1 (JSON)

API documentation

Integrate VanillaX Box listing inspection into your own tools with a REST API and organization API keys.

On this page

  1. 1Overview
  2. 2Authentication
  3. 3Quotas & usage
  4. 4Markets & rules
  5. 5Create an inspection
  6. 6Get results
  7. 7Findings model
  8. 8Apply fixes & re-inspect
  9. 9Outputs & downloads
  10. 10Errors
  11. 11OpenAPI

Overview

A small, predictable REST API. Every response is JSON with camelCase keys; job creation is multipart/form-data so you can upload images directly.

Base URL

URL
https://dodam.modawn.ai/api/v1

Endpoints

Method
GET
Endpoint
/rules
Scope
rules:read
Description
Supported markets, or the rule set for a country + platform
Method
GET
Endpoint
/usage
Scope
jobs:read
Description
Monthly quota and units used
Method
GET
Endpoint
/jobs
Scope
jobs:read
Description
List inspections (cursor pagination)
Method
POST
Endpoint
/jobs
Scope
jobs:write
Description
Create an inspection from images + text (multipart)
Method
GET
Endpoint
/jobs/{id}
Scope
jobs:read
Description
Inspection with assets, signed URLs and latest findings
Method
GET
Endpoint
/jobs/{id}/findings
Scope
jobs:read
Description
Findings for one round with filters
Method
POST
Endpoint
/jobs/{id}/fix
Scope
jobs:write
Description
Apply auto-fixes and re-inspect
Method
POST
Endpoint
/jobs/{id}/reinspect
Scope
jobs:write
Description
Run a new round without changes
Method
GET
Endpoint
/jobs/{id}/report
Scope
jobs:read
Description
Full report as JSON
Method
GET
Endpoint
/jobs/{id}/outputs
Scope
jobs:read
Description
Final assets, or a ZIP with ?format=zip
Method
GET
Endpoint
/openapi.json
Scope
—
Description
OpenAPI 3.1 document (public)
MethodEndpointScopeDescription
GET/rulesrules:readSupported markets, or the rule set for a country + platform
GET/usagejobs:readMonthly quota and units used
GET/jobsjobs:readList inspections (cursor pagination)
POST/jobsjobs:writeCreate an inspection from images + text (multipart)
GET/jobs/{id}jobs:readInspection with assets, signed URLs and latest findings
GET/jobs/{id}/findingsjobs:readFindings for one round with filters
POST/jobs/{id}/fixjobs:writeApply auto-fixes and re-inspect
POST/jobs/{id}/reinspectjobs:writeRun a new round without changes
GET/jobs/{id}/reportjobs:readFull report as JSON
GET/jobs/{id}/outputsjobs:readFinal assets, or a ZIP with ?format=zip
GET/openapi.json—OpenAPI 3.1 document (public)

Requests and responses use UTF-8 JSON, except POST /jobs which accepts multipart/form-data. Timestamps are ISO 8601 in UTC. Ids are UUIDs. Signed file URLs expire after one hour; request the resource again to get fresh links.

Authentication

Requests are authenticated with an organization API key sent as a Bearer token. Keys never expire but can be revoked at any time.

  1. 1
    Open Settings → API keys in the app and create a key. The plaintext key is shown once — store it in your secret manager.
  2. 2
    Send it on every request in the Authorization header. The x-api-key header is accepted as an alternative.
  3. 3
    Keys carry scopes. The default scopes are jobs:read and jobs:write; rules:read is enough for reading rule sets.
Request
curl "https://dodam.modawn.ai/api/v1/usage" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX"
Scope
jobs:read
Description
Read inspections, findings, reports, outputs, usage and rule sets
Scope
jobs:write
Description
Create inspections, apply fixes, request re-inspections
Scope
rules:read
Description
Read markets and rule sets only
Scope
*
Description
All scopes
ScopeDescription
jobs:readRead inspections, findings, reports, outputs, usage and rule sets
jobs:writeCreate inspections, apply fixes, request re-inspections
rules:readRead markets and rule sets only
*All scopes

A missing, malformed or revoked key returns 401 unauthorized; a valid key without the needed scope returns 403 forbidden. Keys are bound to one organization, so every job you create or read belongs to that organization.

401 Unauthorized
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key. Send `Authorization: Bearer dk_live_...`."
  }
}

Note

Keep keys server-side. Never embed dk_live_… keys in mobile apps or browser code — revoke and rotate a key immediately if it leaks.

Quotas & usage

Each organization has a monthly quota of inspection units. Reads are free; inspections and re-inspections consume units.

Action
Create an inspection
Units
1 unit
Action
Re-inspection (also triggered by applying fixes)
Units
1 unit
Action
All GET requests and downloads
Units
Free
ActionUnits
Create an inspection1 unit
Re-inspection (also triggered by applying fixes)1 unit
All GET requests and downloadsFree

Units are counted per organization per calendar month (UTC) across the web app and every API key. When the quota is exhausted, POST /jobs and POST /jobs/{id}/fix respond with 429 quota_exhausted. Admins can see usage by key and by member in Settings → Usage.

GET/usagejobs:read
Request
curl "https://dodam.modawn.ai/api/v1/usage" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX"
Response
{
  "plan": "starter",
  "quota": 500,
  "used": 37,
  "remaining": 463,
  "period": { "start": "2026-09-01T00:00:00.000Z", "end": "2026-10-01T00:00:00.000Z" },
  "byKind": { "inspection": 29, "reinspection": 8 },
  "thisKey": { "id": "3b8f…", "name": "Listing tool (prod)", "used": 12 }
}
429 Too Many Requests
HTTP/1.1 429 Too Many Requests

{ "error": { "code": "quota_exhausted", "message": "Monthly inspection quota exhausted" } }

Markets & rules

Rule sets are composed per country and platform: image spec, title rule, prohibited or risky expressions, IP references and required information.

GET/rulesrules:read | jobs:read

Call it without parameters to list every supported country, platform and product category. Add country and platform to get the exact rule set the engine applies. Regular-expression internals are not exposed; each rule carries its stable code, category, severity, title, description, suggestion and whether it is auto-fixable.

Request
curl "https://dodam.modawn.ai/api/v1/rules" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX"
Request — United States · Amazon
curl "https://dodam.modawn.ai/api/v1/rules?country=US&platform=amazon" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX"
Response
{
  "rules": {
    "country": "US", "countryName": "United States",
    "platform": "amazon", "platformName": "Amazon",
    "image": {
      "minEdge": 500, "recommendedEdge": 1600, "maxEdge": 10000, "maxBytes": 10485760,
      "formats": ["jpeg", "png", "gif"], "aspect": null,
      "mainWhiteBackground": "required", "mainMinFill": 0.85, "noTextOnMain": true
    },
    "title": { "maxLength": 200, "minLength": 15, "recommendedMax": 80, "noAllCaps": true, "noPromoWords": true, "noSpecialChars": true },
    "notes": ["Main image: pure white background (RGB 255,255,255), product fills 85%+ of frame", "…"],
    "textRules": [
      {
        "code": "EXP_MEDICAL_CLAIM", "category": "expression", "severity": "critical",
        "title": "Medical or disease claim",
        "description": "Claims to cure, treat or prevent a disease make the product a drug…",
        "suggestion": "Rephrase as an appearance or comfort benefit…",
        "autoFixable": false, "fields": ["title", "bullets", "description"], "productCategories": null
      }
    ],
    "requiredInfo": [
      { "code": "REQ_ORIGIN", "category": "required_info", "severity": "warning", "title": "Country of origin missing", "autoFixable": true, "productCategories": null }
    ]
  }
}

18 countries · 15 platforms

South Korea KR

Korean

Coupang · Naver Smart Store · Shopify (own store)

United States US

English

Amazon · TikTok Shop · eBay · Walmart Marketplace · Temu · Shopify (own store)

United Kingdom GB

English

Amazon · TikTok Shop · eBay · Temu · Shopify (own store)

Germany DE

German

Amazon · eBay · Temu · Shopify (own store)

France FR

French

Amazon · Temu · Shopify (own store)

Japan JP

Japanese

Amazon · Rakuten · Qoo10 · Temu · Shopify (own store)

China CN

Chinese (Simplified)

Tmall Global · JD Worldwide · Shopify (own store)

Taiwan TW

Chinese (Traditional)

Shopee · Shopify (own store)

Hong Kong HK

Chinese (Traditional) / English

Shopify (own store)

Singapore SG

English

Amazon · Shopee · Lazada · TikTok Shop · Qoo10 · Shopify (own store)

Malaysia MY

Malay / English

Shopee · Lazada · TikTok Shop · Shopify (own store)

Thailand TH

Thai

Shopee · Lazada · TikTok Shop · Shopify (own store)

Vietnam VN

Vietnamese

Shopee · Lazada · TikTok Shop · Shopify (own store)

Indonesia ID

Indonesian

Shopee · Lazada · TikTok Shop · Shopify (own store)

Philippines PH

English / Filipino

Shopee · Lazada · TikTok Shop · Shopify (own store)

Australia AU

English

Amazon · eBay · Temu · Shopify (own store)

United Arab Emirates AE

Arabic / English

Amazon · noon · Shopify (own store)

Saudi Arabia SA

Arabic

Amazon · noon · Shopify (own store)

Platform
Coupang
Code
coupang
Countries
KR
Platform
Naver Smart Store
Code
naver_smartstore
Countries
KR
Platform
Amazon
Code
amazon
Countries
US, GB, DE, FR, JP, SG, AE, SA, AU
Platform
Shopee
Code
shopee
Countries
SG, MY, TH, VN, ID, PH, TW
Platform
Lazada
Code
lazada
Countries
SG, MY, TH, VN, ID, PH
Platform
TikTok Shop
Code
tiktok_shop
Countries
US, GB, SG, MY, TH, VN, ID, PH
Platform
Rakuten
Code
rakuten
Countries
JP
Platform
Qoo10
Code
qoo10
Countries
JP, SG
Platform
Tmall Global
Code
tmall_global
Countries
CN
Platform
JDJD Worldwide
Code
jd_worldwide
Countries
CN
Platform
noon
Code
noon
Countries
AE, SA
Platform
eBay
Code
ebay
Countries
US, GB, DE, AU
Platform
Walmart Marketplace
Code
walmart
Countries
US
Platform
Temu
Code
temu
Countries
US, GB, DE, FR, JP, AU
Platform
Shopify (own store)
Code
shopify
Countries
All
PlatformCodeCountries
CoupangcoupangKR
Naver Smart Storenaver_smartstoreKR
AmazonamazonUS, GB, DE, FR, JP, SG, AE, SA, AU
ShopeeshopeeSG, MY, TH, VN, ID, PH, TW
LazadalazadaSG, MY, TH, VN, ID, PH
TikTok Shoptiktok_shopUS, GB, SG, MY, TH, VN, ID, PH
RakutenrakutenJP
Qoo10qoo10JP, SG
Tmall Globaltmall_globalCN
JDJD Worldwidejd_worldwideCN
noonnoonAE, SA
eBayebayUS, GB, DE, AU
Walmart MarketplacewalmartUS
TemutemuUS, GB, DE, FR, JP, AU
Shopify (own store)shopifyAll

Product categories

beautysupplementfoodfashionelectronicshomebabytoyspetother

Passing a product category enables category-specific rules — supplement disclaimers, allergen labels, toy age grading and so on.

Preview the rules in the app

Create an inspection

Upload the detail-page images and listing text in one multipart request. The engine runs synchronously and the response already contains the findings.

POST/jobsjobs:write
Field
images
Type
file[]
Required
Required
Description
Images (JPEG, PNG, WEBP, GIF), up to your plan limit (free 5, starter 12, growth 20). Repeat the part for each file. The whole request must stay under about 4.5 MB — larger bodies are rejected with 413 before reaching the API, so downscale or send fewer images per request.
Field
country
Type
string
Required
Required
Description
ISO 3166-1 alpha-2, e.g. US. See GET /rules.
Field
platform
Type
string
Required
Required
Description
Platform code, e.g. amazon. Must be available in that country.
Field
name
Type
string
Required
Optional
Description
Inspection name shown in the app. Defaults to the product title.
Field
product_category
Type
string
Required
Optional
Description
One of beauty, supplement, food, fashion, electronics, home, baby, toys, pet, other.
Field
title
Type
string
Required
Optional
Description
Product title (≤ 500 characters).
Field
bullets
Type
string
Required
Optional
Description
Key features as a JSON array of strings, or newline-separated text.
Field
description
Type
string
Required
Optional
Description
Product description (≤ 20,000 characters).
Field
main_index
Type
integer
Required
Optional
Description
Index of the main image inside images. Default 0.
Field
locale
Type
string
Required
Optional
Description
en or ko — language for suggestions. Default en.
FieldTypeRequiredDescription
imagesfile[]RequiredImages (JPEG, PNG, WEBP, GIF), up to your plan limit (free 5, starter 12, growth 20). Repeat the part for each file. The whole request must stay under about 4.5 MB — larger bodies are rejected with 413 before reaching the API, so downscale or send fewer images per request.
countrystringRequiredISO 3166-1 alpha-2, e.g. US. See GET /rules.
platformstringRequiredPlatform code, e.g. amazon. Must be available in that country.
namestringOptionalInspection name shown in the app. Defaults to the product title.
product_categorystringOptionalOne of beauty, supplement, food, fashion, electronics, home, baby, toys, pet, other.
titlestringOptionalProduct title (≤ 500 characters).
bulletsstringOptionalKey features as a JSON array of strings, or newline-separated text.
descriptionstringOptionalProduct description (≤ 20,000 characters).
main_indexintegerOptionalIndex of the main image inside images. Default 0.
localestringOptionalen or ko — language for suggestions. Default en.
Request — curl
curl -X POST "https://dodam.modawn.ai/api/v1/jobs" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX" \
  -F "name=Vitamin C serum — Amazon US" \
  -F "country=US" \
  -F "platform=amazon" \
  -F "product_category=beauty" \
  -F "title=Glow Vitamin C Serum 30ml" \
  -F 'bullets=["20% pure vitamin C", "Cures acne in 3 days"]' \
  -F "description=Brightening serum for all skin types." \
  -F "main_index=0" \
  -F "images=@main.jpg" \
  -F "images=@detail-1.jpg" \
  -F "images=@detail-2.jpg"
Request — Node.js 20+
import { openAsBlob } from "node:fs";

const form = new FormData();
form.append("name", "Vitamin C serum — Amazon US");
form.append("country", "US");
form.append("platform", "amazon");
form.append("title", "Glow Vitamin C Serum 30ml");
form.append("bullets", JSON.stringify(["20% pure vitamin C", "Cures acne in 3 days"]));
form.append("images", await openAsBlob("main.jpg"), "main.jpg");
form.append("images", await openAsBlob("detail-1.jpg"), "detail-1.jpg");

const res = await fetch("https://dodam.modawn.ai/api/v1/jobs", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.DODAM_API_KEY}` },
  body: form,
});
const { job, findings } = await res.json();
console.log(job.score, job.verdict, findings.length);

The request blocks while the engine runs, typically 1–5 seconds for a handful of images. The response has the same shape as GET /jobs/{id}: the job with score and verdict, the assets with signed URLs and the findings of round 1.

Response
HTTP/1.1 201 Created
Location: /api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33

{
  "job": {
    "id": "6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33",
    "name": "Vitamin C serum — Amazon US",
    "status": "review",
    "round": 1,
    "score": 74,
    "verdict": "needs_fix",
    "market": { "country": "US", "countryName": "United States", "platform": "amazon", "platformName": "Amazon", "productCategory": "beauty" },
    "text": { "title": "Glow Vitamin C Serum 30ml", "bullets": ["20% pure vitamin C", "Cures acne in 3 days"], "description": "Brightening serum for all skin types." },
    "summary": { "critical": 1, "warning": 2, "info": 1, "byCategory": { "spec": 1, "expression": 1, "required_info": 2 }, "assets": 3, "engine": "rules", "durationMs": 842 },
    "aiEnriched": false,
    "source": "api",
    "createdAt": "2026-09-02T09:14:03.120Z",
    "completedAt": "2026-09-02T09:14:04.011Z"
  },
  "assets": [
    { "id": "a7d0…", "filename": "main.jpg", "role": "main", "mime": "image/jpeg", "width": 1200, "height": 1200, "sizeBytes": 412088,
      "currentVersion": 1, "originalUrl": "https://…/v1.jpg?token=…", "currentUrl": "https://…/v1.jpg?token=…", "versions": [] }
  ],
  "findings": [
    {
      "id": "f1e2…", "assetId": "a7d0…", "round": 1,
      "category": "spec", "severity": "critical", "priority": 1,
      "code": "IMG_BG_NOT_WHITE",
      "title": "Main image background is not pure white",
      "evidence": { "location": "image", "measured": "91% white", "expected": "≥ 98% white", "source": "rules" },
      "suggestion": "Whiten the background to RGB 255,255,255.",
      "fix": { "type": "whiten_background", "threshold": 235 },
      "autoFixable": true, "status": "open"
    },
    {
      "id": "f2c9…", "assetId": null, "round": 1,
      "category": "expression", "severity": "critical", "priority": 1,
      "code": "EXP_MEDICAL_CLAIM",
      "title": "Medical or disease claim",
      "evidence": { "location": "bullet:2", "matched": "Cures acne", "source": "rules" },
      "suggestion": "Rephrase as an appearance or comfort benefit, e.g. “helps reduce the look of blemishes”, or remove the claim.",
      "fix": null, "autoFixable": false, "status": "open"
    },
    {
      "id": "f3a1…", "assetId": null, "round": 1,
      "category": "required_info", "severity": "warning", "priority": 2,
      "code": "REQ_ORIGIN",
      "title": "Country of origin missing",
      "suggestion": "Add “Country of origin: Republic of Korea” to the description.",
      "fix": { "type": "append_text", "field": "description", "text": "Country of origin: Republic of Korea" },
      "autoFixable": true, "status": "open"
    }
  ],
  "rounds": [1]
}

Tip

Sending bullets as a JSON array preserves each feature exactly. Set main_index when the first image is not the hero image — main-image rules (white background, fill ratio, no text) only apply to that asset.

Get results

List inspections with cursor pagination, fetch a single inspection with signed image URLs, or page through findings per round.

GET/jobsjobs:read

Returns the newest inspections first. limit is 1–100 (default 20). Filter with status, country or platform. When nextCursor is not null, pass it as cursor to fetch the next page.

Request
curl "https://dodam.modawn.ai/api/v1/jobs?limit=20&status=review" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX"

# next page
curl "https://dodam.modawn.ai/api/v1/jobs?limit=20&cursor=2026-09-02T09:14:03.120Z" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX"
Response
{
  "jobs": [ { "id": "6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33", "name": "Vitamin C serum — Amazon US", "status": "review", "round": 1, "score": 74, "verdict": "needs_fix", "…": "…" } ],
  "nextCursor": "2026-09-02T09:14:03.120Z",
  "limit": 20
}
GET/jobs/{id}jobs:read

Everything about one inspection: the job, every image asset with originalUrl, currentUrl and its fix versions, plus the findings of the latest round. Signed URLs are valid for one hour.

Request
curl "https://dodam.modawn.ai/api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX"
GET/jobs/{id}/findingsjobs:read

Findings for a given round (default: latest), optionally filtered by category, severity and status. Previous rounds keep their findings, so you can show how a listing improved after fixes.

Request
curl "https://dodam.modawn.ai/api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33/findings?round=1&severity=critical" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX"
Response
{
  "jobId": "6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33",
  "round": 1,
  "latestRound": 2,
  "rounds": [1, 2],
  "score": null,
  "verdict": null,
  "findings": [ { "id": "f1e2…", "code": "IMG_BG_NOT_WHITE", "severity": "critical", "status": "fixed", "…": "…" } ]
}

Note

A job is completed when the latest round passes, and review while findings remain. Amazon-style markets (US, GB, DE, FR, JP, SG, AE, SA, AU) enforce the strictest main-image spec — check assets[].role to find the main image.

Findings model

Every issue is a finding with a category, a severity, a stable rule code, evidence, a suggestion and, when possible, an executable fix action.

Categories

Code
spec
Meaning
Platform spec violation: image size, ratio, format, file size, background, title length and style
Code
expression
Meaning
Prohibited or risky expression: medical and absolute claims, superlatives, promo words, external contact details
Code
rights
Meaning
IP and rights risk: third-party brands, characters, celebrities, regulator endorsements
Code
required_info
Meaning
Missing required information: origin, responsible person, disclaimers, local-language content, certifications
Code
quality
Meaning
Image quality risk: blur, low brightness or contrast, blank frames, unreadable files
CodeMeaning
specPlatform spec violation: image size, ratio, format, file size, background, title length and style
expressionProhibited or risky expression: medical and absolute claims, superlatives, promo words, external contact details
rightsIP and rights risk: third-party brands, characters, celebrities, regulator endorsements
required_infoMissing required information: origin, responsible person, disclaimers, local-language content, certifications
qualityImage quality risk: blur, low brightness or contrast, blank frames, unreadable files

Severities

Code
critical
Weight
−15
Priority
1
Code
warning
Weight
−5
Priority
2
Code
info
Weight
−1
Priority
3
CodeWeightPriority
critical−151
warning−52
info−13

Score and verdict

The score starts at 100 and subtracts 15 per critical, 5 per warning and 1 per info finding (floored at 0).

score = max(0, 100 − (15 × critical + 5 × warning + 1 × info))

  • pass — score ≥ 85 and no critical finding
  • needs_fix — score 60–84, or any critical finding
  • fail — score < 60

Finding statuses

Status
open
Meaning
Detected in the latest round and not yet decided
Status
accepted
Meaning
Reviewer agreed with the finding (still eligible for auto-fix)
Status
dismissed
Meaning
Reviewer marked it as not applicable
Status
disputed
Meaning
Reviewer disagrees; kept for the record
Status
fixed
Meaning
Applied through POST /jobs/{id}/fix — set automatically
StatusMeaning
openDetected in the latest round and not yet decided
acceptedReviewer agreed with the finding (still eligible for auto-fix)
dismissedReviewer marked it as not applicable
disputedReviewer disagrees; kept for the record
fixedApplied through POST /jobs/{id}/fix — set automatically

Fix actions

When autoFixable is true, fix describes the exact action VanillaX Box will run. Image actions create a new asset version; text actions rewrite the job's title, bullets or description.

Type
resize
Description
Resize (and optionally pad to square) to the platform's min / max edge
Type
convert
Description
Re-encode as jpeg, png or webp
Type
compress
Description
Reduce file size below maxBytes
Type
whiten_background
Description
Push near-white background pixels to pure white
Type
crop_to_content
Description
Crop margins so the product fills the frame
Type
strip_metadata
Description
Remove EXIF / ICC metadata
Type
replace_text
Description
Replace `from` with `to` in the given text field
Type
append_text
Description
Append a required line to the given text field
TypeDescription
resizeResize (and optionally pad to square) to the platform's min / max edge
convertRe-encode as jpeg, png or webp
compressReduce file size below maxBytes
whiten_backgroundPush near-white background pixels to pure white
crop_to_contentCrop margins so the product fills the frame
strip_metadataRemove EXIF / ICC metadata
replace_textReplace `from` with `to` in the given text field
append_textAppend a required line to the given text field

Job statuses

Status
processing
Meaning
Engine is running (only visible on very large uploads)
Status
review
Meaning
Latest round has findings to review
Status
fixing
Meaning
Fixes are being applied
Status
completed
Meaning
Latest round passed
Status
failed
Meaning
Engine error — retry with POST /jobs/{id}/reinspect
StatusMeaning
processingEngine is running (only visible on very large uploads)
reviewLatest round has findings to review
fixingFixes are being applied
completedLatest round passed
failedEngine error — retry with POST /jobs/{id}/reinspect
Rule codes (26 text rules · 55 required-info rules · 20 image rules)ShowHide

Image (IMG_*) and title (TITLE_*)

IMG_FORMATIMG_TOO_SMALLIMG_BELOW_RECOMMENDEDIMG_TOO_LARGEIMG_FILE_TOO_BIGIMG_ASPECTIMG_BG_NOT_WHITEIMG_BG_RECOMMEND_WHITEIMG_TRANSPARENTIMG_FILL_LOWIMG_BLURRYIMG_SOFTIMG_DARKIMG_BLANKIMG_LOW_CONTRASTIMG_METADATAIMG_UNREADABLETITLE_TOO_LONGTITLE_LONG_MOBILETITLE_TOO_SHORTTITLE_ALL_CAPSTITLE_MISSING

Expressions and rights (EXP_*)

EXP_MEDICAL_CLAIMEXP_ANTI_MEDICALEXP_REGULATOR_APPROVALEXP_WEIGHT_LOSSEXP_SKIN_WHITENINGEXP_WHITENINGEXP_CLINICALEXP_ABSOLUTE_NATURALEXP_ABSOLUTE_SAFEEXP_SUPERLATIVE_BESTEXP_SUPERLATIVE_NO1EXP_CN_ABSOLUTEEXP_INSTANTEXP_INSTANT_TIMEEXP_MIRACLEEXP_COMPARATIVEEXP_EXTERNAL_CONTACTEXP_PROMO_TITLEEXP_EMOJI_TITLEEXP_PUNCTUATIONRGT_AWARD_ENDORSEMENTRGT_BRAND_REFERENCERGT_REPLICARGT_CELEBRITYRGT_PATENTRGT_OFFICIAL

Required information (REQ_*)

REQ_ORIGINREQ_INGREDIENTSREQ_NET_CONTENTREQ_SHELF_LIFEREQ_ALLERGENREQ_AGE_GRADEREQ_FIBER_CONTENTREQ_CAREREQ_BATTERYREQ_KR_PRODUCT_NOTICEREQ_KR_CONSUMER_CONTACTREQ_KR_CERTIFICATION_REVIEWREQ_US_FDA_DISCLAIMERREQ_US_SUPPLEMENT_FACTSREQ_US_NUTRITIONREQ_US_FCCREQ_US_CPSIAREQ_GB_RPREQ_GB_UKCAREQ_GB_ALLERGEN_ENREQ_EU_RPREQ_EU_CEREQ_DE_LANGREQ_EU_WEEEREQ_FR_LANGREQ_FR_TRIMANREQ_JP_LANGREQ_JP_SELLERREQ_JP_COSMETIC_CLASSREQ_JP_PSEREQ_JP_STREQ_CN_LANGREQ_CN_CROSS_BORDERREQ_CN_CCCREQ_TW_LANGREQ_HK_LANGREQ_TH_LANGREQ_TH_FDAREQ_VN_LANGREQ_ID_LANGREQ_ID_BPOMREQ_ID_HALALREQ_MY_NPRAREQ_MY_HALALREQ_PH_FDAREQ_SG_HSAREQ_AU_RCMREQ_AU_AICISREQ_AE_ARABICREQ_AE_ESMAREQ_AE_HALALREQ_SA_ARABICREQ_SA_SFDAREQ_SA_SABERREQ_SA_HALAL

Apply fixes & re-inspect

Send the ids of auto-fixable findings to apply them. VanillaX Box creates a new version of each touched image, updates the text and runs a new round.

POST/jobs/{id}/fixjobs:write

Pass the ids of findings from the current round that are autoFixable and still open or accepted. Text fixes are applied to the listing text; image fixes produce version n + 1 of each touched asset. The job is then re-inspected and the response contains the new round (1 unit).

Request
curl -X POST "https://dodam.modawn.ai/api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33/fix" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{ "findingIds": ["f1e2…", "f3a1…"] }'
Response
{
  "applied": 2,
  "round": 2,
  "score": 85,
  "verdict": "needs_fix",
  "job": { "id": "6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33", "status": "review", "round": 2, "score": 85, "verdict": "needs_fix", "…": "…" },
  "assets": [
    { "id": "a7d0…", "filename": "main.jpg", "role": "main", "currentVersion": 2, "currentUrl": "https://…/v2.jpg?token=…",
      "versions": [ { "version": 2, "url": "https://…/v2.jpg?token=…", "appliedFindingIds": ["f1e2…"], "appliedFixes": [ { "type": "whiten_background", "threshold": 235 } ] } ] }
  ],
  "findings": [ { "id": "f4b7…", "round": 2, "code": "EXP_MEDICAL_CLAIM", "severity": "critical", "status": "open", "…": "…" } ],
  "rounds": [1, 2]
}

Note

Findings that cannot be fixed automatically — for example a medical claim that needs rewriting — keep fix: null. Update your listing text, then call POST /jobs/{id}/reinspect or create a new inspection with the corrected content.

POST/jobs/{id}/reinspectjobs:write

Runs a fresh round on the current assets and text without changing anything, which is useful after a manual review or when rules are updated. The optional note is stored in the job timeline. Costs 1 unit.

Request
curl -X POST "https://dodam.modawn.ai/api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33/reinspect" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{ "note": "Text updated in our PIM" }'

Outputs & downloads

Retrieve the final version of every image, the report and a ZIP bundle. Downloads are logged in the inspection's download history.

GET/jobs/{id}/outputsjobs:read

One entry per image with the signed URL of its latest version, the current listing text, and links to the report and ZIP. URLs expire after urlExpiresInSeconds; call the endpoint again for fresh ones.

Request
curl "https://dodam.modawn.ai/api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33/outputs" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX"
Response
{
  "jobId": "6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33",
  "round": 2,
  "score": 85,
  "verdict": "needs_fix",
  "assets": [
    { "id": "a7d0…", "filename": "main.jpg", "role": "main", "currentVersion": 2, "url": "https://…/v2.jpg?token=…", "mime": "image/jpeg", "width": 1600, "height": 1600, "sizeBytes": 388120 }
  ],
  "text": { "title": "Glow Vitamin C Serum 30ml", "bullets": ["20% pure vitamin C", "Cures acne in 3 days"], "description": "Brightening serum for all skin types.\nCountry of origin: Republic of Korea" },
  "reportUrl": "https://dodam.modawn.ai/api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33/report",
  "zipUrl": "https://dodam.modawn.ai/api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33/outputs?format=zip",
  "urlExpiresInSeconds": 3600
}
GET/jobs/{id}/outputs?format=zipjobs:read

Streams application/zip containing final/ (every image at its latest version, named by order, role and version), report.json and listing-text.txt. Each download is written to the inspection's download log.

Request
curl -L "https://dodam.modawn.ai/api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33/outputs?format=zip" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX" \
  -o final-assets.zip
GET/jobs/{id}/reportjobs:read

The full report: inspection metadata, market, text, summary, findings of the latest round, history per round, assets with every version, the applied rule highlights and the event timeline. The same document is embedded in the ZIP.

Request
curl "https://dodam.modawn.ai/api/v1/jobs/6f1c2a4e-8d3b-4f0a-9c1e-2b7d5e9a1f33/report" \
  -H "Authorization: Bearer dk_live_XXXXXXXXXXXXXXXXXXXXXXXX" | jq .report.summary

Errors

Errors use conventional HTTP status codes and a JSON body with a stable machine-readable code.

Example
HTTP/1.1 400 Bad Request

{
  "error": {
    "code": "validation_error",
    "message": "Invalid request: country must be a 2-letter ISO code",
    "details": [ { "field": "country", "message": "country must be a 2-letter ISO code" } ]
  }
}
HTTP
400
Code
validation_error
Meaning
A parameter or field is missing or invalid — details lists the fields
HTTP
401
Code
unauthorized
Meaning
No key, malformed key, unknown or revoked key
HTTP
403
Code
forbidden
Meaning
Key lacks the scope, or the job belongs to another organization
HTTP
404
Code
not_found
Meaning
Unknown job id
HTTP
415
Code
unsupported_media_type
Meaning
POST /jobs body is not multipart/form-data
HTTP
429
Code
quota_exhausted
Meaning
The organization's monthly quota is used up
HTTP
500
Code
internal_error
Meaning
Unexpected failure — safe to retry
HTTPCodeMeaning
400validation_errorA parameter or field is missing or invalid — details lists the fields
401unauthorizedNo key, malformed key, unknown or revoked key
403forbiddenKey lacks the scope, or the job belongs to another organization
404not_foundUnknown job id
415unsupported_media_typePOST /jobs body is not multipart/form-data
429quota_exhaustedThe organization's monthly quota is used up
500internal_errorUnexpected failure — safe to retry

Tip

Branch on error.code, not on the message — messages may be reworded, codes are stable. Retry 500 with exponential back-off; never retry 4xx without changing the request.

OpenAPI

The whole API is described by an OpenAPI 3.1 document that you can import into Postman, Insomnia or an SDK generator.

OpenAPI 3.1 (JSON)
URL
https://dodam.modawn.ai/api/v1/openapi.json
Example
curl "https://dodam.modawn.ai/api/v1/openapi.json" -o vanillaxbox-openapi.json

# e.g. generate a TypeScript client
npx openapi-typescript vanillaxbox-openapi.json -o vanillaxbox-api.d.ts

The document's servers entry always points at the deployment you fetched it from, so a generated client targets the right environment without extra configuration.

Questions about the API? Contact your VanillaX Box account manager.