# PrestaShop product images over the Webservice API
> Generate the sizes with SocialCutter and upload them to PrestaShop over the Webservice image endpoint, assigned to the product.
- URL: https://socialcutter.theboomer.dev/en/guides/prestashop/
- Idioma: en
- Familia: cms
- Actualizado: 2026-09-24
- Palabras clave: PrestaShop, Webservice, images/products, API key, PHP, Python, product images
## Why pre-generate the sizes

A PrestaShop product page shows the same photo in the grid, in the category listing, in the cart and in recommendations. Each slot crops to its own ratio, following the theme's rules.

The flow is: **one master goes in, SocialCutter returns every size, and PrestaShop gets the right one in each slot**. The `cover` crop, which is the default mode, is **centred**: it scales the image and splits the excess evenly on both sides. Leave some margin in the master so nothing important is trimmed.

| Where it goes in the store | SocialCutter destination | Size |
|---|---|---|
| Main product image | `instagram` `post` | 1080x1080 (1:1) |
| Second portrait image | `instagram` `story` | 1080x1920 (9:16) |
| Category banner | `facebook` `post` | 1200x630 (1.91:1) |
| Store header | `twitter` `header` | 1500x500 (3:1) |
| Ad or external listing | `facebook` `story` | 1080x1920 (9:16) |

Sizes come from `GET /api/v1/platforms`, which is public. There is no 4:5 in the catalogue: square is 1:1 and portrait is 9:16.

## Versions and permissions

**Versions.** The Webservice exists on both 1.7 and 8, but it is not identical. Fields change, some resources do too, and authentication especially. Work from the documentation for your version:

- PrestaShop 1.7: https://devdocs.prestashop-project.org/1.7/webservice/
- PrestaShop 8: https://devdocs.prestashop-project.org/8/webservice/

Always probe with a read before writing: `GET /api/products/12?output_format=JSON` must return the product. The default format is XML; `output_format=JSON` returns JSON on the versions that support it, and `?schema=blank` describes a resource's schema.

**Permissions.** The key is created in **Advanced Parameters → Webservice**. Permissions are per resource and per verb:

| Resource | Verbs | What for |
|---|---|---|
| `images` | GET, POST, DELETE | Upload and list product images |
| `products` | GET, PUT | Associate the image and read the product |
| `image_types` | GET | List the theme's image types |

If a verb is not ticked, the call fails with an authorisation error even when the key itself is correct.

**Authentication.** The current docs use the `Authorization` header with basic authentication: the key as the username and an empty password. Many installs still accept the key inside the URL (`https://KEY@store.com/api/...`) or the `ws_key` parameter. A key in the URL ends up in server logs, so prefer the header. `curl -u "$PS_KEY:"` builds that header for you.

```bash
export PS_URL="https://your-store.com"
export PS_KEY="WEBSERVICE_KEY"
export SC_KEY="sc_your_key"
```

## 1. Generate the sizes with SocialCutter

```bash
curl -s -X POST "https://api.socialcutter.theboomer.dev/api/v1/images/process" \
  -H "X-API-Key: $SC_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: product-12-catalogue" \
  -d '{
    "source": { "type": "url", "value": "https://your-cdn.com/master.jpg" },
    "destinations": [
      { "platform": "instagram", "format": "post" },
      { "platform": "instagram", "format": "story" }
    ]
  }' > sc.json

jq '.image_id, (.outputs[] | {url, platform, format, width, height})' sc.json
```

Every output is a public URL. `Idempotency-Key` makes retries safe. For a local master use `POST /api/v1/images/process/upload` (multipart, `file` field, 5 MB maximum) and for volume `POST /api/v1/images/batch`.

## 2. Upload the image to the product

The images resource takes the file through `POST /api/images/products/<id>` in a multipart request. Download the SocialCutter output first and upload it with the key in basic authentication:

```bash
curl -s -o square.jpg "$(jq -r '.outputs[0].url' sc.json)"

# -u with the key and an empty password builds the Authorization header
curl -s -o /dev/null -w "%{http_code}\n" -X POST \
  -u "$PS_KEY:" \
  -F "image=@square.jpg;type=image/jpeg" \
  "$PS_URL/api/images/products/12"
```

The same in PHP, with `CURLFile` to force the file to be sent as a file:

```php
<?php
function ps_upload_image( string $base, string $key, int $product_id, string $path ): int {
    $ch = curl_init( $base . '/api/images/products/' . $product_id );
    curl_setopt_array( $ch, array(
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_USERPWD        => $key . ':',
        CURLOPT_POSTFIELDS     => array(
            'image' => new CURLFile( $path, mime_content_type( $path ), basename( $path ) ),
        ),
        CURLOPT_TIMEOUT => 60,
    ) );

    $body = curl_exec( $ch );
    $code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
    curl_close( $ch );

    if ( $code >= 300 ) {
        throw new RuntimeException( 'PrestaShop returned HTTP ' . $code . ': ' . $body );
    }

    return $code;
}
```

And in Python, with `requests`:

```python
import requests

with open("square.jpg", "rb") as handle:
    response = requests.post(
        f"{BASE}/api/images/products/12",
        auth=(KEY, ""),
        files={"image": ("square.jpg", handle, "image/jpeg")},
        timeout=60,
    )

response.raise_for_status()
print(response.status_code)
```

The file field name and multipart handling can differ between versions: if you get a `400`, check the upload example for your version in the official docs before changing your code.

## 3. Check and associate

List what is attached to the product:

```bash
curl -s -u "$PS_KEY:" "$PS_URL/api/images/products/12?output_format=JSON" | jq '.image[]?.id'
```

If your version does not associate the image on its own, add its `id` to the `associations` → `images` element of the product XML and save the whole product with a `PUT` to `/api/products/<id>`. PrestaShop replaces the entire resource on every `PUT`, so send the full XML the `GET` returned, not a fragment.

To see which sizes the theme generates, query `GET /api/image_types`. The classic ones are `small_default`, `medium_default`, `large_default`, `home_default` and `cart_default`; on 1.7 and 8 the list depends on your theme configuration. Regenerating those thumbnails is triggered from the admin panel (**Design → Image Settings**), and there is no documented Webservice endpoint to fire it. That is why, when you need an exact size or a large batch, pre-generating with SocialCutter is cheaper than depending on a full catalogue regeneration.

## Cost

- **1 use per destination** (platform and format) per request; repeated destinations are not charged twice.
- Failed processings are refunded.
- Plans include API and MCP: Free 3 uses/day, Basic 10, Pro 30, Agency 100.

## Common errors

| Symptom | Cause | Fix |
|---|---|---|
| `401` on every call | Key mistyped, Webservice disabled or IP not allowed | Check **Advanced Parameters → Webservice** and the key's IP list |
| `401` with the key inside the URL | Your version already requires the `Authorization` header | Use `-u "$PS_KEY:"` or `auth=(KEY, "")` |
| `403` on upload | The `images` resource has no POST permission | Add the permission and save the key again |
| `400` on upload | The file field is missing or the MIME type is not an image | Send `image` as multipart with `type=image/jpeg` |
| The image uploads but is not visible | It is not associated with the product, or thumbnails were not regenerated | Add the `id` to `associations` and regenerate from the panel |
| XML rejected on `PUT` | You sent a fragment instead of the full resource | `GET` the product and edit that XML |
| `429` from SocialCutter | Wallet quota exhausted | Check `GET /api/v1/wallet` or upgrade the plan |

## Next steps

- WordPress: [Integrate SocialCutter with WordPress and WooCommerce](/en/guides/wordpress/)
- WooCommerce: [Attach catalogue images to WooCommerce with SocialCutter](/en/guides/woocommerce/)
- Shopify: [Integrate SocialCutter with the Shopify Admin API](/en/guides/shopify/)
- Automation: [Automate image resizing with n8n](/en/guides/n8n/)
- Docs: https://docs.socialcutter.theboomer.dev