0

I'm using createUploadDestinationForResource SP API Uploads API call to get an upload destination for a listing image to be uploaded. It works, but when I'm using returned destination upload URL to upload an image I'm getting an error message:

Conflicting query string parameters: acl, policy

FYI: the destination upload URL returned by createUploadDestinationForResource SP API Uploads API call has the following format (I have put every URL's parameter on a separate line for readability):

https://aplus-media.s3.amazonaws.com/
  ?x-amz-date=20250928T224752Z
  &x-amz-signature={x-amz-signature}
  &x-amz-meta-owner={meta-owner}
  &acl=private
  &key=sc/94cb2445-81fb-4c76-9904-ef258bbc37bc.jpg
  &x-amz-algorithm=AWS4-HMAC-SHA256
  &policy={policy}
  &x-amz-credential={access-key}/20250928/us-east-1/s3/aws4_request

where {policy} is happening to be a base64 encoded JSON:

{"conditions":
   [{"bucket":"aplus-media"},
    {"key":"sc/94cb2445-81fb-4c76-9904-ef258bbc37bc.jpg"},
    {"acl":"private"},
    {"x-amz-meta-owner":"{meta-owner}"},
    {"x-amz-algorithm":"AWS4-HMAC-SHA256"},
    {"x-amz-credential":"{access-key}/20250928/us-east-1/s3/aws4_request"},
    {"x-amz-date":"20250928T224752Z"},
    ["content-length-range",1,3145728
   ]
   ],
 "expiration":"2025-09-29T01:47:52.285Z"}

with values of {meta-owner} and {access-key} being the same as the destination upload url's parameters.

What could be causing this error message in the above context?

Conflicting query string parameters: acl, policy

[UPDATE]

Source code in Python:

import hashlib
import json
import os
import traceback
from typing import Dict

import requests


# Amazon SP API base URL
BASE_URL = 'https://sellingpartnerapi-na.amazon.com/'

# Your AWS credentials and IDs
CLIENT_ID = 'amzn1.application-...'
CLIENT_SECRET = 'amzn1.oa2-cs.v1....'
REFRESH_TOKEN = 'Atzr|IwEBI...'
SELLER_ID = 'A7...'
MARKETPLACE_ID = 'ATVPD...'

# Path to the image file
IMAGE_FILE_PATH = './Images/SKU-0123456789_MainImage.jpg'

def get_access_token(client_id: str, client_secret: str, refresh_token: str) -> tuple:
    """
    Obtain an access token from Amazon SP API.

    Args:
        client_id (str): Your Amazon SP API client ID.
        client_secret (str): Your Amazon SP API client secret.
        refresh_token (str): Your Amazon SP API refresh token.

    Returns:
        tuple: A tuple containing the access token and expiration duration in seconds.
    """
    lwa_authorization_url = 'https://api.amazon.com/auth/o2/token'
    payload = {
        'grant_type': 'refresh_token',
        'client_id': client_id,
        'client_secret': client_secret,
        'refresh_token': refresh_token
    }
    response = requests.post(lwa_authorization_url, data=payload)
    if response.status_code == 200:
        result = response.json()
        access_token = result.get('access_token')
        expires_in_seconds = result.get('expires_in')
        return access_token, expires_in_seconds
    else:
        print(f'Token request error: {response.text}')
        return None, None


def normalize_path(path: str) -> str:
    """
    Normalize and convert the path to an absolute path.

    Args:
        path (str): The original path to normalize.

    Returns:
        str: Normalized absolute path.
    """
    return os.path.normpath(os.path.abspath(path))


def md5_from_jpeg(jpeg_file_path: str) -> str:
    """
    Compute the MD5 hash of a JPEG file.

    Args:
        jpeg_file_path (str): Path to the JPEG file.

    Returns:
        str: Hexadecimal representation of the MD5 hash.
    """
    hasher = hashlib.md5()
    with open(jpeg_file_path, 'rb') as jpeg_file:
        buf = jpeg_file.read()
        hasher.update(buf)
    return hasher.hexdigest()


def create_upload_destination(seller_id: str, marketplace_ids: list, auth_token: str) -> dict:
    """
    Create a temporary URL for uploading an image.

    Args:
        seller_id (str): Your Amazon seller ID.
        marketplace_ids (list): List of marketplace IDs.
        auth_token (str): Authenticated access token.

    Returns:
        dict: Payload returned from the API with the upload URL.
    """
    md5_hash = md5_from_jpeg(normalize_path(IMAGE_FILE_PATH))

    headers = {
        'x-amz-access-token': auth_token,
        'content-type': 'application/json'
    }
    params = {
        'marketplaceIds': marketplace_ids,
        'contentMD5': md5_hash,
        'resource': 'aplus/2020-11-01/contentDocuments',
        'contentType': 'image/jpeg',
    }

    request_url = BASE_URL + 'uploads/2020-11-01/uploadDestinations/aplus/2020-11-01/contentDocuments'

    response = requests.post(request_url, headers=headers, params=params)

    if response.status_code == 201:
        return response.json()['payload']
    else:
        raise ValueError(f'Error creating temp URL: {response.text}')


def upload_image(upload_url: str, image_file_path: str, auth_token: str) -> None:
    """
    Upload an image to the provided URL.

    Args:
        upload_url (str): Temporary URL for uploading the image.
        image_file_path (str): Local path to the image file.
        auth_token (str): Authenticated access token.
    """
    headers = {
        'x-amz-access-token': auth_token,
        'content-type': 'application/jpeg'
    }

    with open(image_file_path, 'rb') as file:
        response = requests.put(upload_url, data=file, headers=headers)
        #
        #  Error
        #    'Conflicting query string parameters: acl, policy'
        #   happens here after the above call to requests.put(...)
        #
        if response.status_code != 200:
            raise ValueError(f'Error loading the image: {response.text}')
        else:
            print('The image successfully loaded.')


if __name__ == '__main__':
    try:
        task_name = 'Upload Listing Image'
        print('=========================================')
        print(f'*** `{task_name}` started ***')
        print('=========================================')

        # Step 1: Compute MD5 hash of the image file
        md5_hash = md5_from_jpeg(normalize_path(IMAGE_FILE_PATH))
        print(f'File = {normalize_path(IMAGE_FILE_PATH)}')
        print(f'MD5 hash = {md5_hash}')

        # Step 2: Acquire an access token
        access_token, expires_in = get_access_token(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN)
        if access_token:
            print(f'Obtained x-amz-access-token: {access_token}')
            print(f'Token will expire in {expires_in} seconds.')
        else:
            print('Failed to get token.')
            exit()

        # Step 3: Create a temporary URL for uploading the image
        temp_upload_payload = create_upload_destination(SELLER_ID, [MARKETPLACE_ID], access_token)
        upload_url = temp_upload_payload['url']

        # Step 4: Upload the image using the temporary URL
        upload_image(upload_url, IMAGE_FILE_PATH, access_token)

    except Exception as error:
        print('---')
        print(f'Runtime error:\n{error}')
        print('---')
        traceback.print_exc()
    finally:
        print('=========================================')
        print(f'*** `{task_name}` completed ***')
        print('=========================================')

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.