Skip to main content

Generating Product Images

The POST /product-image-generator/v1 endpoint generates product imagery for a specific style (brand + number + color + size) and returns signed URLs for rendered files.

It supports:

  • Generating one or many views in a single request
  • Applying one or many logos with placement, sizing, layering, and technique metadata
  • Returning a replayable normalized request payload in the response

Endpoint​

POST https://seddi-public-api-gateway-91po835h.uc.gateway.dev/product-image-generator/v1
Content-Type: application/json

Request body​

{
"brand": "Gildan",
"number": "64000",
"size": "M",
"color": "Black",
"tearAwayLabel": true,
"logos": [
{
"id": "front-logo",
"name": "Primary Logo",
"sourceUrl": "https://example.com/logo.png?X-Goog-Signature=...",
"region": "Chest",
"fill": true,
"size": { "x": 0.09 },
"layer": 1200,
"placement": {
"align": { "x": "left", "y": "center" }
},
"technique": { "name": "Plastisol" }
}
],
"requestedImages": [
{
"format": "image/png",
"resolution": { "x": 1024, "y": 1024 },
"view": "FRONT"
},
{
"format": "image/webp",
"resolution": { "x": 1024, "y": 1024 },
"view": "BACK"
}
]
}

Required fields​

Required top-level fields:

  • brand
  • number
  • size
  • color
  • requestedImages
  • logos

Optional top-level fields:

  • tearAwayLabel (defaults to true)
  • profile (decorator profile slug from GET /data/v1/profiles. Omit to use the style's own regions.)

requestedImages rules​

requestedImages is required for this endpoint.

  • Must contain at least 1 item and at most 4 items
  • There are four camera views. You may request the same view more than once (different format or resolution) up to 4 outputs total. The response includes one images[] entry per requested item.
  • Each item requires:
    • format
    • resolution (x, y, both > 0)
    • view
  • format accepts only:
    • "image/png"
    • "image/jpeg"
    • "image/jpg"
    • "image/webp"
  • view accepts only:
    • "FRONT"
    • "BACK"
    • "LEFT"
    • "RIGHT"

logos rules​

  • Required, minimum 1 graphic and maximum 16 graphics
  • Each graphic sourceUrl file must be 15MB or smaller
  • Each logo requires:
    • sourceUrl (must be https; source file max 15MB)
  • fill is optional and defaults to false. A non-boolean value is rejected. Replay echoes false when the field was omitted.
    • fill: true scales the graphic to fit inside the region and keeps its aspect ratio. size and placement.at are ignored. placement.align can still shift leftover space.
    • Omit fill, or send false, to place the graphic with size and placement.
  • size.x and size.y are width and height in meters in the garment piece plane. Provide one or both. When only one axis is set, the other is inferred from the image aspect ratio. The example 0.09 is about 3.5 inches wide. Omit size entirely and the graphic uses its own dimensions, then scales down to stay inside the region.
  • placement.at.x and placement.at.y are offsets in meters from the point of measure. Larger y is toward the top of the piece.
  • placement.at.measure.from is a point-of-measure name from GET /data/v1/points-of-measure. Matching is case-insensitive on name, then id if you already have one. When several points share a name, the one on the same piece as the logo's region is used. If more than one remains, the closest to that region is used. An unknown name returns 400 with the style's point-of-measure names.
  • region is required unless placement.at is provided. Send the region name from GET /data/v1/regions. An id is accepted when you already have one.
  • placement.at and placement.align are mutually exclusive
  • placement.align is relative to the region. x is left, center, or right. y is top, center, or bottom.
  • placement.at.measure.to accepts only:
    • "Top Left"
    • "Top Center"
    • "Top Right"
    • "Left"
    • "Center"
    • "Right"
    • "Bottom Left"
    • "Bottom Center"
    • "Bottom Right"
  • layer defaults to 1000 when omitted; higher layers render on top
  • transform.rotation is optional. It is the orientation in the finished scene, in degrees (clockwise). Omit it or send 0 so the logo top points toward the top of the scene; 180 flips it. Placement cancels the host piece's arrangement rotation so that scene angle is what you see. The same value is stored on Customizer recipes.
  • colorMap is optional. It is an array of up to 16 { "from": "#rrggbb", "to": "#rrggbb" } pairs. Each from must be unique. The array length is the palette used to recolor the graphic. Omit colorMap, or send [], to keep the original colors.
  • Supported source formats:
    • Raster: png, jpg, jpeg, webp, psd, tif, tiff
    • Vector: svg, ai, eps, pdf
  • technique is optional. When provided, technique.name accepts only:
    • "Plastisol"
    • "Waterbased"
    • "Glitter"
    • "HighDensity"
    • "Puff"
    • "HeatTransfer"
    • "DirectToGarment"
    • "Embroidery"
    • "Patch"
    • "Custom"
  • When technique.name is "Custom", technique.value is required and must be a non-empty string
  • When technique is omitted, the default is "Plastisol" (replay reflects "Plastisol")
  • Rubber is accepted as an alias for Plastisol and is replayed as "Plastisol"

Region aliases​

region may be a style region name from GET /data/v1/regions, an id you already have, or one of the ordinal aliases:

AliasResolves to
FIRSTHighest-priority available decoration region
SECONDSecond-highest-priority available region
THIRDThird-highest-priority available region

Aliases are case-insensitive. Exact name/id matches always win over aliases.

Regions are ordered with this Decorator priority (highest first). Only regions that exist on the style are used:

  1. Chest
  2. WL Chest
  3. Chest Pocket
  4. Front
  5. Back
  6. WR Sleeve
  7. WL Sleeve
  8. Nape
  9. WL Hip
  10. WR Hip
  11. WL Hem
  12. WR Hem
  13. Back Neck Label

Any other region names on the style sort after this list, alphabetically by name.

If the ordinal slot is already used by another logo in the same request, the next unused region is chosen. If the style has fewer regions than the ordinal, the last region is used. Unknown names return 400 with the list of available regions.

{
"sourceUrl": "https://example.com/logo.png",
"region": "FIRST",
"fill": true
}

Use an exact name from Style Data when you need a specific placement (for example "Chest" or "Back").

Place from a point of measure by sending placement.at and omitting fill (or sending false). x and y are meters from that point:

{
"sourceUrl": "https://example.com/logo.png",
"fill": false,
"size": { "x": 0.09 },
"placement": {
"at": {
"x": 0,
"y": -0.05,
"measure": { "from": "Center Front Neck", "to": "Top Center" }
}
}
}

cURL example​

curl -X POST "https://seddi-public-api-gateway-91po835h.uc.gateway.dev/product-image-generator/v1" \
-H "x-api-key: $SEDDI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"brand": "Gildan",
"number": "64000",
"size": "M",
"color": "Black",
"logos": [
{
"sourceUrl": "https://example.com/logo.png",
"region": "FIRST",
"fill": true
}
],
"requestedImages": [
{
"format": "image/png",
"resolution": { "x": 1024, "y": 1024 },
"view": "FRONT"
}
]
}'

Python example​

import os
import requests

payload = {
"brand": "Gildan",
"number": "64000",
"size": "M",
"color": "Black",
"logos": [
{
"sourceUrl": "https://example.com/logo.png",
"region": "Chest",
"fill": True,
}
],
"requestedImages": [
{"format": "image/png", "resolution": {"x": 1024, "y": 1024}, "view": "FRONT"},
{"format": "image/webp", "resolution": {"x": 1024, "y": 1024}, "view": "BACK"},
],
}

response = requests.post(
"https://seddi-public-api-gateway-91po835h.uc.gateway.dev/product-image-generator/v1",
json=payload,
headers={"x-api-key": os.environ["SEDDI_API_KEY"]},
)

response.raise_for_status()
print(response.json())

Response shape​

{
"styleId": "uuid",
"logos": [
{
"id": "front-logo",
"sourceUrl": "https://example.com/logo.png?X-Goog-Signature=...",
"originalFilePath": "logos-for-generators/<cacheKey>/original.png",
"processedFilePath": "logos-for-generators/<cacheKey>/processed.png",
"originalSignedUrl": "https://...",
"processedSignedUrl": "https://..."
}
],
"images": [
{
"view": "FRONT",
"format": "image/png",
"resolution": { "x": 1024, "y": 1024 },
"filePath": "product-image-generator/<styleId>/<file>.png",
"signedUrl": "https://..."
}
],
"request": {
"brand": "Gildan",
"number": "64000",
"size": "M",
"color": "Black",
"tearAwayLabel": true,
"requestedImages": [
{
"format": "image/png",
"resolution": { "x": 1024, "y": 1024 },
"view": "FRONT"
}
]
}
}

Key response notes:

  • images[].signedUrl and the logo signed URLs last 30 minutes
  • logos includes original and processed file references for every submitted logo. Those files live under logos-for-generators/<cacheKey>/
  • request is replayable and normalized (defaults and resolved values are expanded)

Behavior notes​

  • Style selection uses first match by brand + number + color + size
  • tearAwayLabel=false removes scene logos marked as tear-away labels
  • Brand logos are removed if org-brand approval cannot be verified (fail closed)
  • Higher layer values render on top of lower values
  • For vector uploads, conversion to PNG is handled automatically before render
Generation time

Rendering time depends on image count, resolution, and logo processing complexity. Build asynchronous UX or loading states into your integration.