LegitGrailsLegitGrails
Status unavailable
  • Developers
  • API Reference
LegitGrails API
    OverviewQuickstartIntegration setupAuthenticationCatalogOrdersPhotosWebhooksRate limitsErrorsChangelog
API Reference
LegitGrails API

Photos

Upload local photo files before creating an order, then associate the URL from each successful upload result with a catalog photo index. If review requests more evidence, resolve every current request through the order-specific update endpoint. Both writes require orders:write; complete schemas are in the API reference.

Choose photo indexes

Query GET /v1/integrations/catalog/photo_indexes with the selected category, brand, and optional model:

TerminalCode
curl "$LEGITGRAILS_BASE_URL/catalog/photo_indexes?category_code=bag&brand_code=gucci&model_code=gucci-bag-gg-marmont&locale=en" \ --header "Authorization: Bearer $LEGITGRAILS_API_KEY"

Use each entry's machine-readable code as index_code. Include every entry marked required: true, and do not exceed its photo_limit. See Catalog for the full classification lookup.

Upload photo files

POST /v1/integrations/photos accepts one or more photos parts as multipart/form-data:

TerminalCode
curl --request POST "$LEGITGRAILS_BASE_URL/photos" \ --header "Authorization: Bearer $LEGITGRAILS_API_KEY" \ --form "photos=@./overall.jpg" \ --form "photos=@./inside-label.jpg"

The HTTP 200 response preserves file order. Check each result's status:

Code
[ { "status": "uploaded", "url": "https://media.legitgrails.com/uploads/tusd/example-overall", "original_name": "overall.jpg" }, { "status": "uploaded", "url": "https://media.legitgrails.com/uploads/tusd/example-label", "original_name": "inside-label.jpg" } ]

File type, size, and image-dimension validation happens before upload. If any file fails validation, the entire request is rejected. Once validation passes, HTTP 200 means the batch was processed, even if an individual upload-gateway operation failed. A failed result has no url:

Code
{ "status": "failed", "original_name": "inside-label.jpg", "error": { "code": "photo-upload-failed", "message": "Photo could not be uploaded" } }

Supported image formats are JPEG, PNG, HEIC, HEIF, WebP, and AVIF. Send no more than 10 files in one request. Each file can be up to 100 MiB. Images are also limited to 8,000 pixels on either side and 50,000,000 total pixels.

The upload does not assign an index or attach anything to an order. Match each successful result to its local file and use only URLs from uploaded results in the create request. Order photo URLs from other hosts are rejected.

Code
{ "brand_code": "gucci", "category_code": "bag", "photos": [ { "index_code": "overall-picture", "url": "https://media.legitgrails.com/uploads/tusd/example-overall" }, { "index_code": "inside-label", "url": "https://media.legitgrails.com/uploads/tusd/example-label" } ] }

Respond to an update-photos request

Retrieve the order to read its current photos_to_resubmit request.

TerminalCode
curl "$LEGITGRAILS_BASE_URL/orders/<order-id>?locale=en" \ --header "Authorization: Bearer $LEGITGRAILS_API_KEY"
Code
{ "id": "<order-id>", "status": "update-photos", "outcome": null, "outcome_locale": null, "delayed": false, "classification": { "brand_code": "gucci", "category_code": "bag", "model_code": "gucci-bag-gg-marmont", "model_name": "GG Marmont", "model_name_locale": "GG Marmont" }, "due_date": "2026-08-05T15:30:00.000Z", "updated_at": "2026-08-04T17:05:11.000Z", "photos_to_resubmit": [ { "index_code": "overall-picture", "name": "Overall picture", "name_locale": "Overall picture", "condition": "unclear", "condition_locale": "Unclear photo", "requirements": ["better-lighting", "zoom-in"], "requirements_locale": [ "Use better lighting", "Move closer to the item" ], "comment": "Avoid reflections and include the full item.", "reference_photo_url": null, "max_photos": 2 } ] }

Use index_code, condition, and requirements for machine logic; use the localized fields, comment, and optional reference_photo_url for display. max_photos is the limit for this index in the current update round.

Submit the current round

Upload local replacements first, then send their URLs to POST /v1/integrations/orders/{id}/update_photos using the returned order ID.

TerminalCode
curl --request POST "$LEGITGRAILS_BASE_URL/orders/<order-id>/update_photos" \ --header "Authorization: Bearer $LEGITGRAILS_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "photos": [ { "index_code": "overall-picture", "url": "https://media.legitgrails.com/uploads/tusd/example-replacement-1" }, { "index_code": "overall-picture", "url": "https://media.legitgrails.com/uploads/tusd/example-replacement-2" } ], "note": "Two clearer overall photos are attached." }'

A valid submission returns 202 Accepted:

Code
{ "id": "<order-id>", "status": "accepted" }

Acceptance is not an authenticity result. Continue monitoring the detail endpoint or webhooks.

Update rules

  • Resolve every index_code in the current photos_to_resubmit; partial submissions are rejected together.
  • Each entry supplies exactly one resolution: a managed url returned by POST /photos, or is_unable_to_provide: true.
  • Repeat an index_code for multiple URLs, up to its max_photos.
  • For one index, is_unable_to_provide: true must be the only entry; do not mix it with URLs.
  • Do not submit indexes absent from the current request.
  • note is optional and limited to 1,000 characters.

An order can have multiple update rounds. Resolve only the current round, then keep monitoring. See Errors for error responses.

Last modified on September 4, 2026
OrdersWebhooks
On this page
  • Choose photo indexes
  • Upload photo files
  • Respond to an update-photos request
    • Submit the current round
    • Update rules
JSON
JSON
JSON
JSON
JSON