2D Mockups (Setup)
Place your artwork onto a product photo. Turn any apparel, poster, or packshot image into a reusable mockup, then render unlimited designs onto its print areas.
When to use this
2D is a two-step flow
How It Works
A 2D mockup is created once and reused for every design. Creating it is synchronous by default: the printable areas on your product photo are found and prepared, and the call returns the ready mockup in one call, no polling. Pass is_async: true for a queued job with webhook delivery instead. Rendering is also synchronous by default and accepts is_async: true when you want a queued 2d_render job.
POST /api/v1/sudoai/2d-mockups returns the ready mockup with its print-area quads. Costs 25 credits.is_async: true, poll the job or receive a webhook first, then fetch the mockup.POST /api/v1/sudoai/2d-mockups/{mockup_uuid}/render returns a hosted image. Costs 5 credits.Create once, render forever
What Teams Build With It
One product photo, prepared once, covers very different jobs. These are the three shapes this flow usually takes.
Add to cart on your store
Shoppers upload their own artwork, see it on your product photo, and buy the version they just made. The rendered image goes on the order.
Learn moreA mockup step inside your product
Give the users of your own app a preview of their design on a real product, without building or running a render backend.
Learn moreMarketing visuals at scale
Turn one product photo into a full campaign set. Swap the artwork per variant, market, or seasonal drop and render every image from the same mockup.
Learn moreAuthentication
Every request uses your API key in the x-api-key header. Get a key from your Dashboard.
x-api-keystringRequiredYour SudoMock API key, starting with sm_.
Content-TypestringRequiredMust be application/json for POST and PUT requests.
Idempotency-KeystringOptional. Safely retry a create request without charging twice. Max 255 characters. Reusing a key with a different body returns 409.
Create a Mockup
/api/v1/sudoai/2d-mockupsSend exactly one image source. By default the create is synchronous: the call blocks until the mockup is ready and returns it with a 201 Created in one call, no polling. Pass is_async: true to queue it instead and get a 202 Accepted job you can poll (or receive a webhook). Either way, if the image cannot be used for a mockup, the 25 credits are refunded automatically.
Request Body
source_urlstringPublic HTTPS URL of the product photo. Provide either source_url or source_base64, not both.
source_base64stringBase64-encoded product photo, with or without a data URL prefix. Provide either source_base64 or source_url, not both.
namestringOptional display name for the mockup. Max 255 characters.
is_asyncbooleanOptional, default false. When false the call returns the finished mockup (201). When true it returns immediately with a 202 job to poll (or a webhook), useful for batch creates.
print_areasarrayOptional list of one to eight print areas. When supplied, SudoMock uses these areas exactly and skips automatic print-area detection.
print_areas[].namestringOptional label for the print area, such as Front or Back. Max 120 characters.
print_areas[].pointsarrayExactly four [x, y] points in source-image pixels, ordered top-left, top-right, bottom-right, bottom-left.
1{2 "source_url": "https://your-domain.com/product-photo.jpg",3 "name": "Classic Tee - Front"4}
Already know the print areas?
print_areas in the create request to use your own one-to-eight four-point areas and skip automatic detection.1{2 "source_url": "https://your-domain.com/product-photo.jpg",3 "name": "Classic Tee - Front",4 "print_areas": [5 {6 "name": "Front",7 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]]8 }9 ]10}
Response (default, synchronous)
1{2 "data": {3 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",4 "name": "Classic Tee - Front",5 "status": "ready",6 "thumbnail_url": "https://cdn.sudomock.com/2d-mockups/9b0a74cd.../thumb.webp",7 "source_width": 2000,8 "source_height": 2400,9 "quads": [10 {11 "print_area_id": "223e4567-e89b-12d3-a456-426614174001",12 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]],13 "sort_order": 014 }15 ],16 "surfaces": [],17 "version": 1,18 "created_at": "2026-07-20T10:00:00Z",19 "updated_at": "2026-07-20T10:00:12Z"20 },21 "success": true22}
The synchronous response is the mockup itself, including its print-area quads, so you can go straight to rendering. See Track and Fetch the Mockup below for the is_async: true job flow.
Track and Fetch the Mockup
/api/v1/sudoai/2d-mockups/{mockup_uuid}You only need this when you pass is_async: true. The synchronous default already returns the mockup. For an async create, poll the job at status_url until its status becomes succeeded (or receive a webhook); the completed job carries the new mockup_uuid. See the Jobs reference for the full poll contract.
1{2 "job_id": "b7f2c1a0-9e34-4d21-8f0a-1c2b3d4e5f60",3 "kind": "2d_create",4 "status": "queued",5 "status_url": "/api/v1/jobs/b7f2c1a0-9e34-4d21-8f0a-1c2b3d4e5f60"6}
1{2 "job_id": "b7f2c1a0-9e34-4d21-8f0a-1c2b3d4e5f60",3 "kind": "2d_create",4 "status": "succeeded",5 "result_url": "/api/v1/sudoai/2d-mockups/9b0a74cd-0ebb-4748-a748-976fec8cc000",6 "mockup_uuid": "9b0a74cd-0ebb-4748-a748-976fec8cc000",7 "error": null,8 "created_at": "2026-07-20T10:00:00Z",9 "updated_at": "2026-07-20T10:00:12Z"10}
Then fetch the mockup itself to read its render targets. Standard print areas are four-corner quads in image coordinates, returned in the quads array. Verified full product surfaces are returned separately in surfaces.
1{2 "data": {3 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",4 "name": "Classic Tee - Front",5 "status": "ready",6 "customizable": true,7 "thumbnail_url": "https://cdn.sudomock.com/2d-mockups/9b0a74cd.../thumb.webp",8 "source_width": 2000,9 "source_height": 2400,10 "quads": [11 {12 "print_area_id": "223e4567-e89b-12d3-a456-426614174001",13 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]],14 "sort_order": 015 }16 ],17 "surfaces": [],18 "version": 1,19 "created_at": "2026-07-20T10:00:00Z",20 "updated_at": "2026-07-20T10:00:12Z"21 },22 "success": true23}
Mockup Fields
data.mockup_idstringRequiredUUID of the mockup. Pass it in the render URL path.
data.namestringRequiredDisplay name of the mockup.
data.statusstringRequiredMockup state: draft, processing, ready, or error. Print areas are usable once ready.
data.customizablebooleanRequiredTrue when this mockup can open a shopper customization session.
data.thumbnail_urlstringPreview thumbnail URL.
data.source_widthintegerSource photo width in pixels. Print-area points are in this coordinate space.
data.source_heightintegerSource photo height in pixels.
data.quadsarrayRequiredPrint areas detected on the photo. Each entry has print_area_id, points, and sort_order.
data.quads[].print_area_idstringRequiredUUID of the print area. Pass this as uuid inside the render print_areas array.
data.quads[].pointsarrayRequiredFour [x, y] corner points, ordered top-left, top-right, bottom-right, bottom-left.
data.quads[].sort_orderintegerRequiredDisplay order of the print area, starting at 0.
data.surfacesarrayRequiredVerified full product surfaces. Empty for a standard print-area mockup.
data.surfaces[].surface_uuidstringUUID of a full product surface. Pass this as surface_uuid inside the render print_areas array.
List Mockups
/api/v1/sudoai/2d-mockupsReturns your 2D mockups newest first. Each item includes its status, thumbnail, source dimensions, and saved print areas.
limitinteger= 20Items per page, from 1 to 100.
offsetinteger= 0Number of items to skip.
customizable_onlyboolean= falseWhen true, return only mockups ready for shopper customization.
1{2 "data": [3 {4 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",5 "name": "Classic Tee - Front",6 "status": "ready",7 "customizable": true,8 "thumbnail_url": "https://cdn.sudomock.com/2d-mockups/9b0a74cd.../thumb.webp",9 "source_width": 2000,10 "source_height": 2400,11 "print_areas": [12 {13 "print_area_id": "223e4567-e89b-12d3-a456-426614174001",14 "name": "Front",15 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]],16 "sort_order": 017 }18 ],19 "version": 1,20 "created_at": "2026-07-20T10:00:00Z",21 "updated_at": "2026-07-20T10:00:12Z"22 }23 ],24 "total": 1,25 "limit": 20,26 "offset": 0,27 "success": true28}
Set Print Areas (Optional)
/api/v1/sudoai/2d-mockups/{mockup_uuid}/print-areasThe print areas prepared at creation work out of the box. Use this endpoint only when you want to override them with your own placement. It replaces all print areas in the order you send, so include every area you want to keep. Available once the mockup is ready.
Want to review or adjust the prepared result visually? A Studio setup session opens the full toolbar where you can refine supported product areas, adjust bounded print areas, and preview placement before saving. See Setting up print areas.
Request Body
print_areasarrayRequiredZero to eight print areas. Array order becomes the sort order. Send an empty array to remove every print area.
print_areas[].pointsarrayRequiredExactly four [x, y] corner points, in image coordinates, ordered top-left, top-right, bottom-right, bottom-left. Each area must be a convex four-point shape inside the source image.
1{2 "print_areas": [3 {4 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]]5 }6 ]7}
1{2 "data": {3 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",4 "print_areas": [5 {6 "print_area_id": "223e4567-e89b-12d3-a456-426614174001",7 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]],8 "sort_order": 09 }10 ]11 },12 "success": true13}
Render Artwork
/api/v1/sudoai/2d-mockups/{mockup_uuid}/renderRender one or more designs onto a mockup you created earlier. Each print area takes an artwork image, a solid color, or both. By default the response returns a hosted image URL synchronously. Set is_async: true to receive a queued job instead.
Choose exactly one target identifier
uuid for a saved entry from data.quads. Use surface_uuid for a verified full product surface from data.surfaces. Do not send both.Request Body
mockup_uuidstringRequiredPath parameter in the URL, not the body: UUID of the 2D mockup to render, from the create job or the get-mockup response.
print_areasarrayRequiredOne to eight render targets. Each uses exactly one uuid or surface_uuid from the get-mockup response.
export_optionsobjectOutput format, size, and quality. Optional; sensible defaults apply.
is_asyncbooleanOptional, default false. When true, returns a 202 2d_render job to poll or receive by webhook.
Print Area Configuration
Artwork or color required
artwork_url (or base64) or a color. You can supply both to tint the artwork.uuidstringThe print_area_id from data.quads. Required when surface_uuid is omitted.
surface_uuidstringThe identifier from data.surfaces. Required when uuid is omitted.
artwork_urlstringURL of the artwork image to place. Provide artwork_url or base64.
base64stringBase64-encoded artwork image. Skips the download step. Provide base64 or artwork_url.
colorstringSolid color overlay in #RRGGBB format (e.g. '#FF0000'). Can be used alone or to tint the artwork.
adjustmentsobjectPer-artwork image adjustments. See Adjustments below.
placementobjectHow the artwork sits inside the print area. See Placement below.
Adjustments
brightnessinteger= 0Brightness (-150 to 150). 0 = no change.
contrastinteger= 0Contrast (-100 to 100). 0 = no change.
saturationinteger= 0Saturation (-100 to 100). -100 = grayscale.
vibranceinteger= 0Vibrance (-100 to 100). Boosts muted tones while protecting skin tones.
opacityinteger= 100Artwork opacity (0 to 100). 0 = transparent, 100 = opaque.
blurinteger= 0Gaussian blur (0 to 100). 0 = sharp.
blend_modeenum= multiplyHow the artwork sits on the product surface. 'multiply' keeps the fabric or material texture visible; 'normal' lays the artwork flat and reproduces the artwork colors exactly; 'screen' keeps a light artwork readable on a dark garment; 'lighten' keeps the artwork only where it is brighter than the surface; 'soft_light' gives a subtle, low-contrast finish; 'overlay' deepens contrast so the artwork reads as part of the material; 'darken' keeps the artwork only where it is darker than the surface. Send 'normal' when a brand color has to match the supplied file.
Keeping a brand color exact
multiply is the default because it looks like a real print: on a black tee a white logo comes out grey, the way ink looks on dark fabric. When a brand color has to match the file you supplied, send "blend_mode": "normal": white stays white and a brand blue stays that blue, whatever the product color. Blend mode is set per print area, so one area can hold an exact logo while another stays on multiply. The other five modes are for a specific look: screen on a dark garment, overlay for stronger contrast, soft_light for a gentle finish, darken and lighten to keep only the darker or lighter parts of the artwork.Placement
positionenum= centerAnchor within the print area: center, top_left, top_center, top_right, center_left, center_right, bottom_left, bottom_center, bottom_right.
coverageinteger= 70Percent of the print area the artwork covers (10 to 100). Ignored when width and height are set.
fitenum= containHow the artwork fits its box: 'contain' fits inside preserving aspect ratio, 'fill' stretches to the bounds, 'cover' fills and crops excess.
widthintegerArtwork width in print-area pixels (1 to 30000). Send it with height; the pair overrides coverage and fit sizing. The axes are independent, so any aspect ratio is allowed.
heightintegerArtwork height in print-area pixels (1 to 30000). Send it with width; sending one alone is rejected rather than guessed.
rotationnumber= 0Rotation in degrees, clockwise positive.
offset_xinteger= 0Horizontal pixel offset from the anchor position.
offset_yinteger= 0Vertical pixel offset from the anchor position.
Export Options
image_formatenum= webpOutput format: webp (30-70% smaller, recommended), png (lossless, quality ignored), or jpg (smallest, no transparency).
image_sizeinteger= 2048Output width in pixels (100 to 10000). Height is derived from the source aspect ratio. Powers of two (1024, 2048, 4096) are recommended.
qualityinteger= 90Compression quality for JPG and WebP (1 to 100). Ignored for PNG.
dpiinteger= nullPrint resolution tag written into the file metadata (72 to 2400). Metadata only; image_size controls the real pixels. For a print file, size image_size = print_inches x dpi.
1{2 "print_areas": [3 {4 "uuid": "223e4567-e89b-12d3-a456-426614174001",5 "artwork_url": "https://your-domain.com/design.png",6 "adjustments": {7 "blend_mode": "multiply",8 "opacity": 959 },10 "placement": {11 "position": "center",12 "coverage": 80,13 "fit": "contain"14 }15 }16 ],17 "export_options": {18 "image_format": "png",19 "image_size": 2048,20 "quality": 9521 }22}
1{2 "print_areas": [3 {4 "surface_uuid": "323e4567-e89b-12d3-a456-426614174002",5 "artwork_url": "https://your-domain.com/design.png",6 "placement": {7 "position": "center",8 "fit": "cover"9 }10 }11 ],12 "export_options": {13 "image_format": "png",14 "image_size": 204815 }16}
Response
1{2 "data": {3 "render_uuid": "9adcc828-1f4e-4a2b-9c3d-2e6f8b0a1d77",4 "print_files": [5 {6 "export_path": "https://cdn.sudomock.com/renders/2d/9b0a74cd.../render.png",7 "duration_ms": 1180,8 "export_format": "png"9 }10 ]11 },12 "success": true13}
data.render_uuidstringIdentifier for this render.
data.print_filesarrayRequiredRendered output files.
data.print_files[].export_pathstringRequiredHosted URL of the rendered image.
data.print_files[].duration_msintegerRender duration in milliseconds.
data.print_files[].export_formatstringOutput format used (png, jpg, or webp).
Asynchronous Response
1{2 "job_id": "c315f78f-d2c7-4541-b240-a9372842de94",3 "kind": "2d_render",4 "status": "queued",5 "status_url": "/api/v1/jobs/c315f78f-d2c7-4541-b240-a9372842de94"6}
Poll status_url or subscribe to 2d_render.succeeded and 2d_render.failed. The completed job puts the rendered image URL in result_url.
No watermark
Prefer no backend? Embed Studio
Security
Delete a 2D Mockup
/api/v1/sudoai/2d-mockups/{mockup_uuid}Permanently deletes a 2D mockup and its print areas. This action cannot be undone.
1{2 "data": {3 "deleted": "9b0a74cd-0ebb-4748-a748-976fec8cc000"4 },5 "success": true6}
Code Examples
1# 1. Create a reusable 2D mockup (synchronous: the call returns the ready mockup)2curl -X POST "https://api.sudomock.com/api/v1/sudoai/2d-mockups" \3 -H "Content-Type: application/json" \4 -H "x-api-key: sm_your_api_key" \5 -d '{6 "source_url": "https://your-domain.com/product-photo.jpg",7 "name": "Classic Tee - Front"8 }'9# -> 201 { "data": { "mockup_id": "...", "quads": [{ "print_area_id": "...", ... }] } }10# Add "is_async": true to get a 202 { "job_id", "status_url" } job to poll instead.1112# 2. Render your artwork onto a print area13curl -X POST "https://api.sudomock.com/api/v1/sudoai/2d-mockups/MOCKUP_UUID/render" \14 -H "Content-Type: application/json" \15 -H "x-api-key: sm_your_api_key" \16 -d '{17 "print_areas": [{18 "uuid": "PRINT_AREA_ID",19 "artwork_url": "https://your-domain.com/design.png",20 "placement": { "position": "center", "coverage": 80 }21 }],22 "export_options": { "image_format": "png", "image_size": 2048 }23 }'
Webhooks
Instead of polling, configure a webhook endpoint to be notified when a creation job finishes. Set it up and verify signatures on the Webhooks page. The 2D creation and asynchronous render flows emit these events:
2d_mockup.readyeventThe mockup was created and its print areas are ready to render.
2d_mockup.rejectedeventThe image was not suitable for a mockup. The payload includes a reason. Credits are refunded.
2d_mockup.failedeventThe creation job failed unexpectedly. Credits are refunded.
2d_render.succeededeventAn asynchronous 2D render finished and result_url is ready.
2d_render.failedeventAn asynchronous 2D render failed.
1{2 "version": 1,3 "event": "2d_mockup.ready",4 "job_id": "b7f2c1a0-9e34-4d21-8f0a-1c2b3d4e5f60",5 "kind": "2d_create",6 "status": "ready",7 "created_at": "2026-07-20T10:00:12Z",8 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",9 "name": "Classic Tee - Front",10 "print_areas": [11 {12 "print_area_id": "223e4567-e89b-12d3-a456-426614174001",13 "points": [[420, 560], [1580, 560], [1600, 1840], [400, 1840]],14 "sort_order": 015 }16 ]17}
1{2 "version": 1,3 "event": "2d_mockup.rejected",4 "job_id": "b7f2c1a0-9e34-4d21-8f0a-1c2b3d4e5f60",5 "kind": "2d_create",6 "status": "rejected",7 "created_at": "2026-07-20T10:00:12Z",8 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",9 "name": "Classic Tee - Front",10 "reason": "The image is not suitable for mockup generation."11}
1{2 "version": 1,3 "event": "2d_mockup.failed",4 "job_id": "b7f2c1a0-9e34-4d21-8f0a-1c2b3d4e5f60",5 "kind": "2d_create",6 "status": "failed",7 "created_at": "2026-07-20T10:00:12Z",8 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",9 "name": "Classic Tee - Front"10}
1{2 "event": "2d_render.succeeded",3 "job_id": "c315f78f-d2c7-4541-b240-a9372842de94",4 "kind": "2d_render",5 "status": "succeeded",6 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",7 "result_url": "https://cdn.sudomock.com/mockup-assets/renders/2d/result.png",8 "error": null,9 "created_at": "2026-07-20T10:00:12Z",10 "export_format": "png",11 "duration_ms": 118012}
1{2 "event": "2d_render.failed",3 "job_id": "c315f78f-d2c7-4541-b240-a9372842de94",4 "kind": "2d_render",5 "status": "failed",6 "mockup_id": "9b0a74cd-0ebb-4748-a748-976fec8cc000",7 "result_url": null,8 "error": {9 "error_code": "RENDER_FAILED",10 "message": "The mockup could not be rendered. Please try again."11 },12 "created_at": "2026-07-20T10:00:12Z"13}
Handle retries safely
job_id and the event name so a repeated delivery is a safe no-op.Error Responses
Invalid input, such as both or neither image source on create, or a print area outside the source image.
1{2 "error_code": "INVALID_SOURCE",3 "message": "Provide exactly one of source_url or source_base64.",4 "detail": "Remove one source field, or add the missing source field.",5 "success": false6}
Missing or invalid API key.
1{2 "detail": "Not authenticated",3 "success": false4}
Not enough credits. Create needs 25 credits, render needs 5. The response includes actionable links and the credit reset time.
1{2 "error": "credits_exhausted",3 "message": "You have used all 500 trial credits. Add a payment method to keep rendering, or start a plan.",4 "actions": [5 { "label": "Add a payment method", "url": "https://sudomock.com/dashboard/billing?action=topup#payg-section" },6 { "label": "Start a plan", "url": "https://sudomock.com/pricing" }7 ]8}
The mockup UUID does not exist or is not owned by your account.
1{2 "detail": "Failed to retrieve mockup",3 "success": false4}
Print areas can only be changed after the mockup is ready, or an Idempotency-Key was reused with a different request body.
1{2 "error_code": "MOCKUP_NOT_SETTABLE",3 "message": "Print areas can only be changed after the mockup is ready.",4 "suggestion": "Wait for the creation job to finish and try again."5}
Rate limit or concurrent render limit exceeded. Retry after the indicated delay.
1{2 "detail": "Rate limit exceeded. Try again in 30 seconds.",3 "error": {4 "type": "rate_limit_exceeded",5 "code": "RATE_LIMIT_EXCEEDED",6 "retry_after": 30,7 "resource": "api"8 }9}