Product Crop Migration

This guide shows how to migrate from the v1 API's /pie/psdService/productCrop endpoint to the v2 API's /v2/execute-actions endpoint.

The Product Crop convenience API automatically removes backgrounds and adds customizable padding - perfect for e-commerce product photography.

Key benefits of the v2 API:

V1 API (Deprecated)

Endpoint: /pie/psdService/productCrop

curl -X POST \
  https://image.adobe.io/pie/psdService/productCrop \
  -H "Authorization: Bearer $token" \
  -H "x-api-key: $apiKey" \
  -H "Content-Type: application/json" \
  -d '{
  "inputs": [
    {
      "href": "<SIGNED_GET_URL>",
      "storage": "external"
    }
  ],
  "outputs": [
    {
      "href": "<SIGNED_POST_URL>",
      "storage": "external",
      "type": "image/jpeg"
    }
  ]
}'

V2 API (Current)

Endpoint: /v2/execute-actions

Using inline ActionJSON

curl -X POST \
  https://photoshop-api.adobe.io/v2/execute-actions \
  -H "Authorization: Bearer $token" \
  -H "x-api-key: $apiKey" \
  -H "Content-Type: application/json" \
  -d '{
  "image": {
    "source": {
      "url": "<SIGNED_GET_URL>"
    }
  },
  "options": {
    "actions": [
      {
        "source": {
          "content": "[{\"_obj\":\"autoCutout\",\"sampleAllLayers\":false},{\"_obj\":\"make\",\"at\":{\"_enum\":\"channel\",\"_ref\":\"channel\",\"_value\":\"mask\"},\"new\":{\"_class\":\"channel\"},\"using\":{\"_enum\":\"userMaskEnabled\",\"_value\":\"revealSelection\"}},{\"_obj\":\"newPlacedLayer\"},{\"_obj\":\"trim\",\"bottom\":true,\"left\":true,\"right\":true,\"top\":true,\"trimBasedOn\":{\"_enum\":\"trimBasedOn\",\"_value\":\"transparency\"}},{\"_obj\":\"canvasSize\",\"height\":{\"_unit\":\"pixelsUnit\",\"_value\":10},\"horizontal\":{\"_enum\":\"horizontalLocation\",\"_value\":\"center\"},\"relative\":true,\"vertical\":{\"_enum\":\"verticalLocation\",\"_value\":\"center\"},\"width\":{\"_unit\":\"pixelsUnit\",\"_value\":10}},{\"_obj\":\"placedLayerConvertToLayers\"},{\"_obj\":\"delete\",\"_target\":[{\"_enum\":\"channel\",\"_ref\":\"channel\",\"_value\":\"mask\"}]},{\"_obj\":\"trim\",\"bottom\":true,\"left\":true,\"right\":true,\"top\":true,\"trimBasedOn\":{\"_enum\":\"trimBasedOn\",\"_value\":\"transparency\"}}]",
          "contentType": "application/json"
        }
      }
    ]
  },
  "outputs": [
    {
      "destination": {
        "url": "<SIGNED_POST_URL>"
      },
      "mediaType": "image/jpeg"
    }
  ]
}'

ActionJSON Definition

The Product Crop action performs 8 distinct operations:

[
  {
    "_obj": "autoCutout",
    "sampleAllLayers": false
  },
  {
    "_obj": "make",
    "at": {
      "_enum": "channel",
      "_ref": "channel",
      "_value": "mask"
    },
    "new": {
      "_class": "channel"
    },
    "using": {
      "_enum": "userMaskEnabled",
      "_value": "revealSelection"
    }
  },
  {
    "_obj": "newPlacedLayer"
  },
  {
    "_obj": "trim",
    "bottom": true,
    "left": true,
    "right": true,
    "top": true,
    "trimBasedOn": {
      "_enum": "trimBasedOn",
      "_value": "transparency"
    }
  },
  {
    "_obj": "canvasSize",
    "height": {
      "_unit": "pixelsUnit",
      "_value": 10
    },
    "horizontal": {
      "_enum": "horizontalLocation",
      "_value": "center"
    },
    "relative": true,
    "vertical": {
      "_enum": "verticalLocation",
      "_value": "center"
    },
    "width": {
      "_unit": "pixelsUnit",
      "_value": 10
    }
  },
  {
    "_obj": "placedLayerConvertToLayers"
  },
  {
    "_obj": "delete",
    "_target": [
      {
        "_enum": "channel",
        "_ref": "channel",
        "_value": "mask"
      }
    ]
  },
  {
    "_obj": "trim",
    "bottom": true,
    "left": true,
    "right": true,
    "top": true,
    "trimBasedOn": {
      "_enum": "trimBasedOn",
      "_value": "transparency"
    }
  }
]

What this action does

  1. Auto Cutout - Automatically detects and isolates the main subject using AI
  2. Create Mask - Creates a layer mask from the auto-generated selection
  3. Convert to Smart Object - Converts layer to smart object for non-destructive editing
  4. First Trim - Removes transparent pixels around the subject to minimize canvas size
  5. Add Canvas Padding - Adds 10 pixels of padding on all sides (default, customizable)
  6. Convert to Layers - Converts smart object back to regular layer
  7. Delete Mask - Removes the layer mask (no longer needed)
  8. Final Trim - Final trim to clean up edges and ensure consistent output

Customizing the padding

The default action uses 10-pixel padding on all sides. To customize:

Modify padding values

Locate the canvasSize step (5th action in the sequence) and modify the _value fields:

Example with 100-pixel padding:

{
  "_obj": "canvasSize",
  "height": {
    "_unit": "pixelsUnit",
    "_value": 100
  },
  "horizontal": {
    "_enum": "horizontalLocation",
    "_value": "center"
  },
  "relative": true,
  "vertical": {
    "_enum": "verticalLocation",
    "_value": "center"
  },
  "width": {
    "_unit": "pixelsUnit",
    "_value": 100
  }
}

Change to percentage-based padding

You can also use percentage-based padding by changing the _unit:

{
  "_obj": "canvasSize",
  "height": {
    "_unit": "percentUnit",
    "_value": 10
  },
  ...
  "width": {
    "_unit": "percentUnit",
    "_value": 10
  }
}

This adds 10% padding to each side.

Common customizations

1. No padding (tight crop)

Remove the canvasSize step entirely or set values to 0:

{
  "_obj": "canvasSize",
  "height": {
    "_unit": "pixelsUnit",
    "_value": 0
  },
  ...
}

2. Asymmetric padding

For different padding on different sides, you'll need to use multiple canvasSize operations or switch to absolute positioning.

3. Add post-processing

You can add additional actions after the product crop sequence:

{
  "options": {
    "actions": [
      {
        "source": {
          "content": "[...product crop actions...{\"_obj\":\"brightnessEvent\",\"brightness\":20}]",
          "contentType": "application/json"
        }
      }
    ]
  }
}

Migration checklist

Migration examples

Basic migration

V1:

{
  "inputs": [{"href": "s3://input.jpg", "storage": "external"}],
  "outputs": [{"href": "s3://output.jpg", "type": "image/jpeg"}]
}

V2:

{
  "image": {"source": {"url": "s3://input.jpg"}},
  "options": {
    "actions": [{
      "source": {
        "content": "[{...ActionJSON...}]",
        "contentType": "application/json"
      }
    }]
  },
  "outputs": [{"destination": {"url": "s3://output.jpg"}, "mediaType": "image/jpeg"}]
}

With custom padding

{
  "image": {"source": {"url": "https://..."}},
  "options": {
    "actions": [{
      "source": {
        "content": "[{...modify canvasSize _value to 100...}]",
        "contentType": "application/json"
      }
    }]
  },
  "outputs": [{"destination": {"url": "https://..."}, "mediaType": "image/png"}]
}

Additional resources

Support

For questions or issues: