Image Layer Operations Migration
This guide helps you migrate image layer and solid color layer operations from v1's /documentCreate and /documentOperations endpoints to v2's /create-composite endpoint.
Overview
The v1 endpoints /pie/psdService/documentCreate and /pie/psdService/documentOperations were used to create documents with image/fill layers and add/edit image/fill layers respectively.
Now in the v2 API, all layer operations are unified into the /v2/create-composite endpoint with the edits.layers array.
Layer types covered in this guide are:
- Image/Pixel Layers - V1
type: "layer"→ V2type: "layer" - Solid Color Layers - V1
type: "fillLayer"→ V2type: "solid_color_layer"
Key migration changes
1. Add operation structure
In the v1 API, the add block was used with insert instructions to specify the placement of the new layer.
{
"type": "layer",
"name": "New Layer",
"add": {
"insertTop": true
},
"input": {
"href": "<URL>",
"storage": "external"
}
}
In the v2 API, one operation block is used with the placement property to specify the placement of the new layer.
{
"type": "layer",
"name": "New Layer",
"image": {
"source": {
"url": "<URL>"
}
},
"operation": {
"type": "add",
"placement": {
"type": "top"
}
}
}
2. Image source property
The v1 API used the input object.
{
"input": {
"href": "<URL>",
"storage": "external"
}
}
The v2 API uses the image.source object.
{
"image": {
"source": {
"url": "<URL>"
}
}
}
3. Layer placement
Layer placement is now specified in the operation.placement property. See the Layer placement migration patterns section for more details.
Adding image layers
V1 approach
The v1 API used the /documentOperations endpoint with the add block to add a new image layer.
curl -X POST \
https://image.adobe.io/pie/psdService/documentOperations \
-H "Authorization: Bearer $token" \
-H "x-api-key: $apiKey" \
-H "Content-Type: application/json" \
-d '{
"inputs": [{
"href": "<SIGNED_GET_URL>",
"storage": "external"
}],
"options": {
"layers": [
{
"type": "layer",
"name": "New Image",
"add": {
"insertTop": true
},
"input": {
"href": "<IMAGE_URL>",
"storage": "external"
}
}
]
},
"outputs": [{
"href": "<SIGNED_POST_URL>",
"storage": "external",
"type": "image/vnd.adobe.photoshop"
}]
}'
V2 approach
curl -X POST \
https://photoshop-api.adobe.io/v2/create-composite \
-H "Authorization: Bearer $token" \
-H "x-api-key: $apiKey" \
-H "Content-Type: application/json" \
-d '{
"image": {
"source": {
"url": "<SIGNED_GET_URL>"
}
},
"edits": {
"layers": [
{
"type": "layer",
"name": "New Image",
"image": {
"source": {
"url": "<IMAGE_URL>"
}
},
"operation": {
"type": "add",
"placement": {
"type": "top"
}
}
}
]
},
"outputs": [
{
"destination": {
"url": "<SIGNED_POST_URL>"
},
"mediaType": "image/vnd.adobe.photoshop"
}
]
}'
Layer placement migration patterns
In the v1 API, the placement options were controlled by these parameters:
insertTop: true- Add at the top of the layer stackinsertBottom: true- Add at the bottom of the layer stackinsertAbove: {id: 123}- Add above a specific layer by IDinsertBelow: {name: "Layer"}- Add below a specific layer by nameinsertInto: {name: "Group"}- Add inside a group by name
In the v2 API, the corresponding placement options are controlled by the operation.placement property:
type: "top"- Add at toptype: "bottom"- Add at bottomtype: "above"withreferenceLayer- Above specific layertype: "below"withreferenceLayer- Below specific layertype: "into"withreferenceLayer- Inside a group
Insert at Top
V1:
{
"add": {
"insertTop": true
}
}
V2:
{
"operation": {
"type": "add",
"placement": {
"type": "top"
}
}
}
Insert at Bottom
V1:
{
"add": {
"insertBottom": true
}
}
V2:
{
"operation": {
"type": "add",
"placement": {
"type": "bottom"
}
}
}
Insert Above Layer
V1:
{
"add": {
"insertAbove": {
"name": "Background"
}
}
}
V2:
{
"operation": {
"type": "add",
"placement": {
"type": "above",
"referenceLayer": {
"name": "Background"
}
}
}
}
Insert Below Layer
V1:
{
"add": {
"insertBelow": {
"id": 123
}
}
}
V2:
{
"operation": {
"type": "add",
"placement": {
"type": "below",
"referenceLayer": {
"id": 123
}
}
}
}
Insert Into Group
V1:
{
"add": {
"insertInto": {
"name": "My Group"
}
}
}
V2:
{
"operation": {
"type": "add",
"placement": {
"type": "into",
"referenceLayer": {
"name": "My Group"
}
}
}
}
Solid Color Layers
V1 approach: fillLayer
curl -X POST \
https://image.adobe.io/pie/psdService/documentOperations \
-H "Authorization: Bearer $token" \
-H "x-api-key: $apiKey" \
-H "Content-Type: application/json" \
-d '{
"inputs": [{
"href": "<SIGNED_GET_URL>",
"storage": "external"
}],
"options": {
"layers": [
{
"type": "fillLayer",
"name": "Red Fill",
"add": {
"insertTop": true
},
"fill": {
"solidColor": {
"rgb": {
"red": 255,
"green": 0,
"blue": 0
}
}
}
}
]
},
"outputs": [{
"href": "<SIGNED_POST_URL>",
"storage": "external",
"type": "image/vnd.adobe.photoshop"
}]
}'
V2 approach
curl -X POST \
https://photoshop-api.adobe.io/v2/create-composite \
-H "Authorization: Bearer $token" \
-H "x-api-key: $apiKey" \
-H "Content-Type: application/json" \
-d '{
"image": {
"source": {
"url": "<SIGNED_GET_URL>"
}
},
"edits": {
"layers": [
{
"type": "solid_color_layer",
"name": "Red Fill",
"fill": {
"solidColor": {
"rgb": {
"red": 255,
"green": 0,
"blue": 0
}
}
},
"operation": {
"type": "add",
"placement": {
"type": "top"
}
}
}
]
},
"outputs": [
{
"destination": {
"url": "<SIGNED_POST_URL>"
},
"mediaType": "image/vnd.adobe.photoshop"
}
]
}'
Solid Color Layer Changes
V1: type: "fillLayer" with nested rgb object
{
"type": "fillLayer",
"fill": {
"solidColor": {
"rgb": {
"red": 255,
"green": 0,
"blue": 0
}
}
}
}
V2: type: "solid_color_layer" with direct color properties
{
"type": "solid_color_layer",
"fill": {
"solidColor": {
"rgb": {
"red": 255,
"green": 0,
"blue": 0
}
}
}
}
Editing Existing Layers
V1 approach: edit block
{
"options": {
"layers": [
{
"name": "Existing Layer",
"edit": {},
"visible": false,
"blendOptions": {
"opacity": 75
}
}
]
}
}
V2 approach
{
"edits": {
"layers": [
{
"name": "Existing Layer",
"isVisible": false,
"opacity": 75
}
]
}
}
data-variant=info
data-slots=text
operation: { "type": "edit" }, then reference the layer by name or ID and specify the properties to change. The Core API Server rejects requests that omit the operation field.Replacing Layer Content
V1 approach
{
"options": {
"layers": [
{
"name": "Existing Layer",
"edit": {},
"input": {
"href": "<NEW_IMAGE_URL>",
"storage": "external"
}
}
]
}
}
V2 approach
In V2, use operation: { "type": "edit" } and identify the layer by id or name. The replacement image is supplied via image.source.url in the same request:
{
"edits": {
"layers": [
{
"type": "layer",
"id": 751,
"name": "Existing Layer",
"operation": {
"type": "edit"
},
"image": {
"source": {
"url": "<NEW_IMAGE_URL>"
}
}
}
]
}
}
data-variant=info
data-slots=text
id or name) must be an image/pixel layer in the document.Layer Positioning
Using Bounds
Both V1 and V2 support explicit positioning:
V1:
{
"type": "layer",
"name": "Positioned Image",
"bounds": {
"left": 100,
"top": 100,
"width": 500,
"height": 300
}
}
V2: (Same pattern)
{
"type": "layer",
"name": "Positioned Image",
"bounds": {
"left": 100,
"top": 100,
"width": 500,
"height": 300
}
}
Alignment Options
V1: horizontalAlign and verticalAlign
{
"type": "layer",
"horizontalAlign": "center",
"verticalAlign": "center"
}
V2: Uses placement alignment
{
"type": "layer",
"operation": {
"type": "add",
"placement": {
"type": "custom",
"horizontalAlignment": "center",
"verticalAlignment": "center"
}
}
}
Fill to Canvas
V1: fillToCanvas property
{
"type": "layer",
"fillToCanvas": true
}
V2: Not yet available
data-variant=warning
data-slots=text
fillToCanvas property from V1 is not yet available in V2.Creating Documents with Image Layers
V1 approach: documentCreate
{
"options": {
"document": {
"width": 1000,
"height": 1000,
"resolution": 72,
"fill": "white",
"mode": "rgb"
},
"layers": [
{
"type": "layer",
"name": "Logo",
"input": {
"href": "<IMAGE_URL>",
"storage": "external"
}
}
]
}
}
V2 approach
{
"document": {
"width": 1000,
"height": 1000,
"resolution": {"unit": "density_unit", "value": 72},
"fill": {
"solidColor": {
"red": 255,
"green": 255,
"blue": 255
}
},
"mode": "rgb"
},
"edits": {
"layers": [
{
"type": "layer",
"name": "Logo",
"image": {
"source": {
"url": "<IMAGE_URL>"
}
},
"operation": {
"type": "add"
}
}
]
}
}
Migration checklist
When migrating image layer operations from v1 to v2:
- Change
inputtosourcefor image references - Change
href/storagetourl/storageType(or omit storageType for external) - Replace
addblock withoperation.type: "add" - Convert placement:
insertTop→placement.type: "top" - Convert placement:
insertBottom→placement.type: "bottom" - Convert placement:
insertAbove→placement.type: "above"withreferenceLayer - Convert placement:
insertBelow→placement.type: "below"withreferenceLayer - Convert placement:
insertInto→placement.type: "into"withreferenceLayer - Change
type: "fillLayer"totype: "solid_color_layer" - Remove explicit
edit: {}block for modifications - Convert
blendOptions.opacitytoopacity(top-level property) - Convert
visibletoisVisible - Lock: Change
lockedtoprotectionarray (see Advanced Layer Operations) - Note:
fillToCanvasnot yet available in V2
Common migration issues
Missing placement for an add operation
The v2 API requires explicit placement for an add operation. Always specify placement type.
{
"operation": {
"type": "add",
"placement": {
"type": "top"
}
}
}
Storage type changes
V1: Required explicit storage type
{
"href": "<URL>",
"storage": "external"
}
V2: Storage type optional, defaults to external
{
"url": "<URL>"
}
Solid color structure
V1: Nested rgb object
{
"fill": {
"solidColor": {
"rgb": {
"red": 255,
"green": 0,
"blue": 0
}
}
}
}
V2: Same nested structure
{
"fill": {
"solidColor": {
"rgb": {
"red": 255,
"green": 0,
"blue": 0
}
}
}
}
Complete Migration Example
V1 documentOperations:
{
"inputs": [
{
"href": "<SIGNED_GET_URL>",
"storage": "external"
}
],
"options": {
"layers": [
{
"type": "layer",
"name": "Hero Image",
"add": {
"insertTop": true
},
"input": {
"href": "<IMAGE_URL>",
"storage": "external"
},
"bounds": {
"left": 0,
"top": 0,
"width": 1920,
"height": 600
}
},
{
"type": "fillLayer",
"name": "Background",
"add": {
"insertBottom": true
},
"fill": {
"solidColor": {
"rgb": {
"red": 240,
"green": 240,
"blue": 240
}
}
}
}
]
},
"outputs": [
{
"href": "<SIGNED_POST_URL>",
"storage": "external",
"type": "image/vnd.adobe.photoshop"
}
]
}
V2 create-composite:
{
"image": {
"source": {
"url": "<SIGNED_GET_URL>"
}
},
"edits": {
"layers": [
{
"type": "layer",
"name": "Hero Image",
"image": {
"source": {
"url": "<IMAGE_URL>"
}
},
"bounds": {
"left": 0,
"top": 0,
"width": 1920,
"height": 600
},
"operation": {
"type": "add",
"placement": {
"type": "top"
}
}
},
{
"type": "solid_color_layer",
"name": "Background",
"fill": {
"solidColor": {
"rgb": {
"red": 240,
"green": 240,
"blue": 240
}
}
},
"operation": {
"type": "add",
"placement": {
"type": "bottom"
}
}
}
]
},
"outputs": [
{
"destination": {
"url": "<SIGNED_POST_URL>"
},
"mediaType": "image/vnd.adobe.photoshop"
}
]
}
Feature Availability
Currently Available in V2
- ✅ Add image layers
- ✅ Add solid color layers
- ✅ Edit existing layers
- ✅ Replace layer content
- ✅ Layer positioning (bounds)
- ✅ Layer placement (top, bottom, above, below, into)
- ✅ Layer visibility and opacity
V1 Features Not Yet in V2
- ⏳
fillToCanvasproperty - ⏳ Some advanced alignment options
Next steps
- Review Layer Operations Overview for general concepts
- Check Text Layers for text operations
- See Advanced Operations for masks and transforms