PHP
Article

Adding Products to Your eBay Store with the Trading API

By Wern Ancheta

Using eBay's API to Develop a Product Management App

In this third and final part of our eBay Trading API series, we’ll be building the product adding functionality into our application.

Creating new Products

Now that we’re done with the store settings, we can begin with writing the code for the controller that would handle the creation of products. Under the controllers directory, create a new file and name it Product.php.

<?php
class Product extends \SlimController\SlimController{
    
}

Next, create the newAction method. This will render the new.twig file under the templates/product directory. This is the view that renders the form for creating new products.

public function newAction(){   
    $page_data = array(
        'is_productpage' => 'true'
    );
    $this->render('product/new', $page_data);       
}

Next create the view:

{% extends "/base.twig" %}
{% block content %}
{{ parent() }}
<div class="row">
  <div class="col-md-4">  
    <div class="alert alert-{{ flash.message.type }}">
      {{ flash.message.text }}

      {% for r in flash.message.data %}
      <li>{{ r[0] }}</li>
      {% endfor %}
    </div>
  </div>
</div>
<div class="row">
  <div class="col-md-6">
    <form class="form-horizontal" method="POST" action="{{ baseUrl }}/products/create">
      <fieldset>
        <legend>Create new Product</legend>
        <div class="form-group">
          <label for="title" class="col-lg-2 control-label">Title</label>
          <div class="col-lg-10">
            <input type="text" class="form-control" id="title" name="title" value="{{ flash.form.title }}">
          </div>
        </div>
        <div class="form-group">
          <label for="category" class="col-lg-2 control-label">Category</label>
          <div class="col-lg-10" id="categories-container">
            
          </div>
        </div>
        <div class="form-group">
          <label for="price" class="col-lg-2 control-label">Price</label>
          <div class="col-lg-10">
            <input type="text" class="form-control" id="price" name="price" value="{{ flash.form.price }}">
          </div>
        </div>
        <div class="form-group">
          <label for="quantity" class="col-lg-2 control-label">Quantity</label>
          <div class="col-lg-10">
            <input type="text" class="form-control" id="quantity" name="quantity" value="{{ flash.form.quantity }}">
          </div>
        </div>      
        <div class="form-group">
          <label for="brand" class="col-lg-2 control-label">Brand</label>
          <div class="col-lg-10">
            <input type="text" class="form-control" id="brand" name="brand" value="{{ flash.form.brand }}">
          </div>
        </div>
        <div class="form-group">
          <label for="description" class="col-lg-2 control-label">Description</label>
          <div class="col-lg-10">
            <textarea class="form-control" rows="3" id="description" name="description" value="{{ flash.form.description }}">{{ flash.form.description }}</textarea>
          </div>
        </div>
        
        <div class="form-group">
          <div class="col-lg-10 col-lg-offset-2">
            <button type="submit" class="btn btn-primary">Add Product</button>
          </div>
        </div>
      </fieldset>
    </form>
  </div>

  <div class="col-md-6">
    <h5>Upload Photos</h5>
    <form action="{{ baseUrl }}/upload" method="POST" class="dropzone" id="photosdropzone" enctype="multipart/form-data"></form>
  </div>
</div>


{% include 'partials/categories.html' %}
{% endblock %}

Breaking it down, at the beginning is where we output the alert message. We’ll pass along the values for this later on when we add the code for creating products. flash is a global variable where session data that we pass along is temporarily saved:

<div class="alert alert-{{ flash.message.type }}">
    {{ flash.message.text }}
    {% for r in flash.message.data %}
    <li>{{ r[0] }}</li>
    {% endfor %}
</div>

Next is the product title and other required product details. Take note that only the product title, description, quantity, price, and a product image are required in most cases. Here, we’ve added brand because in some cases it’s required. The general term for this kind of field is a conditional field. It usually depends on the category of the product whether it’s required or not. Some categories require more fields than others so be sure to check the documentation on the AddItem API Call to make sure you’re not missing anything.

<input type="text" class="form-control" id="title" name="title" value="{{ flash.form.title }}">

For the product category, we’re going to load it later on via AJAX since it will depend on the product title entered by the user.

<label for="category" class="col-lg-2 control-label">Category</label>
<div class="col-lg-10" id="categories-container">
                
</div>

Next is the form that the user will use for uploading the product images:

<form action="{{ baseUrl }}/upload" method="POST" class="dropzone" id="photosdropzone" enctype="multipart/form-data"></form>

This uses the /upload route for processing the uploaded files. Declare the method for processing this route in the Product class:

public function uploadAction(){

    $storage = new \Upload\Storage\FileSystem('uploads');
    $file = new \Upload\File('file', $storage);

    $new_filename = uniqid();
    $file->setName($new_filename);

    $_SESSION['uploads'][] = $new_filename . '.' . $file->getExtension();

    $file->addValidations(array(
        new \Upload\Validation\Mimetype(array('image/png', 'image/gif', 'image/jpg')),
        new \Upload\Validation\Size('6M')
    ));

    $errors = array();

    try{
        $file->upload();
    }catch(Exception $e){
        $errors = $file->getErrors();
    }

    $response_data = array(
        'errors' => $errors
    );

    echo json_encode($response_data);

}

Breaking the uploadAction() method down, first we specify the upload path. In this case we’re using the uploads directory. Make sure you give it the necessary directory permissions so we can actually upload files to it:

$storage = new \Upload\Storage\FileSystem('uploads');

Next, we specify the field we use for uploading files. Going back to the form for uploading, we didn’t specify any <input type="file"> fields in there. That’s because we don’t need to. By default dropzone uses file as the default field name for uploading files so we specify it as the first argument for the File method, the second argument is the storage which we created earlier:

$file = new \Upload\File('file', $storage);

Next, we give the file a unique name. You can be creative here if you want, but if you’re not feeling creative then just use the uniqid() method to generate a unique file name:

$new_filename = uniqid();
$file->setName($new_filename);

Push the file name into the uploads session item so we can use it later on.

$_SESSION['uploads'][] = $new_filename . '.' . $file->getExtension();

Next, we add some file validation. We just tell it to only accept png, gif, and jpg images, and the max file size should only be 6Mb.

$file->addValidations(array(
        new \Upload\Validation\Mimetype(array('image/png', 'image/gif', 'image/jpg')),
        new \Upload\Validation\Size('6M')
    ));

Lastly, we try to upload the file and assign any errors we get and return them to the client side. But we won’t really be making use of this error on the client side since dropzone already has us covered. It displays an x mark for the uploaded file if the file didn’t pass the validation:

$errors = array();

try{
  $file->upload();
}catch(Exception $e){
  $errors = $file->getErrors();
}

$response_data = array(
  'errors' => $errors
);

echo json_encode($response_data);

Going back to the template for adding new products, we include a partial. This is the template that will be used for showing the suggested product categories.

{% include 'partials/categories.html' %}

It contains the following:

{% raw %}
<script id="categories-template" type="text/x-handlebars-template">
{{#each categories}}
<div class="radio">
  <label>
    <input type="radio" name="category_id" id="category_id" value="{{id}}">
    {{name}}
  </label>
</div>
{{/each}}
</script>
{% endraw %}

In the above template, we’re using Handlebars. Its syntax collides with twig syntax so we have to wrap it in {% raw %} tags to make sure twig doesn’t parse it.

Next, create the dropzone-options.js file under the /assets/js directory and add the following:

(function(){

  Dropzone.options.photosdropzone = {

    acceptedFiles: "image/*",
    autoProcessQueue: true,
    uploadMultiple: false,
    maxFiles: 5
  };

})();

That allows us to specify the options for the dropzone. Here’s a breakdown of each option:

  • acceptedFiles – the type of file that can be uploaded.
  • autoProcessQueue – a boolean value for specifying whether to process the queue immediately or not.
  • uploadMultiple – a boolean value for specifying whether to allow multiple file uploads. In this case we selected false but it doesn’t mean we can’t upload more than one image. It means that we can’t upload more than one image at the same time.
  • maxFiles – an integer value for specifying the max number of files which can be uploaded.

Next, create the new-product.js file and add the following:

(function(){
  var categories_template = Handlebars.compile($("#categories-template").html());

  $('#title').blur(function(){
    var title = $(this).val();
    $.post(
      '/tester/ebay_trading_api/categories', 
      {
        'title' : title
      },
      function(response){
        var categories = JSON.parse(response);
        var html = categories_template({'categories' : categories});
        
        $('#categories-container').html(html);
      }
    );
  });
})();

What the code above does is make a POST request every time the user tabs out of the product title field. The request then returns an array of objects containing the suggested categories based on the product title. The method which is used in this call is in the Product class. What it does is call the getSuggestedCategories() method in the Ebay class, passing in the product title as the argument. The response is then converted into a JSON string and echoed out:

public function categoriesAction(){
    $suggested_categories = $this->app->ebay->getSuggestedCategories($_POST['title']);
    echo json_encode($suggested_categories);
}

Open up the Ebay class and add the following method:

public function getSuggestedCategories($title){

  $requestBody = '<?xml version="1.0" encoding="utf-8"?>
    <GetSuggestedCategoriesRequest xmlns="urn:ebay:apis:eBLBaseComponents">
    <RequesterCredentials>
        <eBayAuthToken>' . $this->user_token . '</eBayAuthToken>
      </RequesterCredentials>
      <Query>' . $title . '</Query>
    </GetSuggestedCategoriesRequest>';

  $response = $this->request('GetSuggestedCategories', $requestBody);

  $suggested_categories = array();
  if($response->Ack == 'Success'){

    foreach($response->SuggestedCategoryArray->SuggestedCategory as $category){
      $suggested_categories[] = array(
        'id' => json_decode(json_encode($category->Category->CategoryID), true)[0],
        'name' => json_decode(json_encode($category->Category->CategoryName), true)[0]
      );
    }
  }

  return $suggested_categories;
}

What the method above does is make a request to the GetSuggestedCategories API method. This call accepts the product title as its argument, as passed in the Query field. If the call is successful, it returns an array of suggested categories. We just need to extract the category id and category name from the result it returns.

Now we’re ready to write the createAction method. This is where we save the product details into the database and create the product on ebay.

public function createAction(){
    
    $v = new Valitron\Validator($_POST);
    $v->rule('required', array('title', 'category_id', 'price', 'quantity', 'brand', 'description'));
    $v->rule('numeric', 'price');
    $v->rule('integer', 'quantity');
    if($v->validate()){
       
        if($query = $this->app->db->prepare("INSERT INTO products SET title = ?, category_id = ?, price = ?, qty = ?, brand = ?, description = ?")){

            $store_settings_result = $this->app->db->query("SELECT payment_profile, return_profile, shipping_profile, out_of_stock_control, get_it_fast, category_prefill,
                category_mapping, condition_type, country_code_type, currency_code, dispatch_time, optimal_picturesize,
                listing_duration, listing_type, item_location, postal_code, store_name, county,
                street, ebay_website, shippingservice_priority, shipping_service, shippingservice_cost, shippingservice_additionalcost
                FROM store_settings WHERE id = 1");
            $store_settings = $store_settings_result->fetch_object();

            $response = $this->app->ebay->addItem($store_settings, $_POST);

            if($response->Ack == 'Success'){

                $title = $_POST['title'];
                $category_id = $_POST['category_id'];
                $price = $_POST['price'];
                $qty = $_POST['quantity'];
                $brand = $_POST['brand'];
                $description = $_POST['description'];

                $query->bind_param("ssdiss", $title, $category_id, $price, $qty, $brand, $description);
                $query->execute();

                $this->app->flash('message', array('type' => 'success', 'text' => 'Product was created!'));
            }else{

                $long_message = json_decode(json_encode($response->Errors->LongMessage), true);
                $this->app->flash('message', array('type' => 'danger', 'text' => $long_message[0]));

            }

        }
        
        
    }else{
        
        $this->app->flash('form', $_POST);
        $this->app->flash('message', array(
            'type' => 'danger', 
            'text' => 'Please fix the following errors', 
            'data' => $v->errors())
        );
        
    }  

    $this->app->redirect('/tester/ebay_trading_api/products/new'); 
}

Breaking it down. First, we declare a new instance of valitron, passing in all the values that are currently stored in the $_POST global variable:

$v = new Valitron\Validator($_POST);

Next we add the rules. Basically all the fields are required, the price should be a numeric value, and the quantity should be an integer. We specified that using the rule method which takes up the actual rule as the first argument, and the name of the field as the second argument:

$v->rule('required', array('title', 'price', 'quantity', 'brand', 'description'));
$v->rule('numeric', 'price');
$v->rule('integer', 'quantity');

Next we validate using the validate() method. If this returns true then the validation passed, otherwise it didn’t. If it returns false then we take all the POST data and save it into the session along with the error messages returned by valitron.

$this->app->flash('form', $_POST);
$this->app->flash('message', array(
  'type' => 'danger', 
  'text' => 'Please fix the following errors', 
  'data' => $v->errors())
);

If the validation passes, we retrieve the store settings from the database and supply them as an argument for the addItem() method along with the contents of the $_POST variable. The addItem() method creates the product on eBay. If the call is successful, we create a prepared statement for adding the details of the product in the database. Once that’s done we flash a message into the session saying that the product was created. If the call is not successful then we pass the response returned from the API along with a message that the product was not created.

$store_settings_result = $this->app->db->query("SELECT payment_profile, return_profile, shipping_profile, out_of_stock_control, get_it_fast, category_prefill,
    category_mapping, condition_type, country_code_type, currency_code, dispatch_time, optimal_picturesize,
    listing_duration, listing_type, item_location, postal_code, store_name, county,
    street, ebay_website, shippingservice_priority, shipping_service, shippingservice_cost, shippingservice_additionalcost
    FROM store_settings WHERE id = 1");
$store_settings = $store_settings_result->fetch_object();

$response = $this->app->ebay->addItem($store_settings, $_POST);

if($response->Ack == 'Success'){

    if($query = $this->app->db->prepare("INSERT INTO products SET title = ?, category_id = ?, price = ?, qty = ?, brand = ?, description = ?")){

        $title = $_POST['title'];
        $category_id = $_POST['category_id'];
        $price = $_POST['price'];
        $qty = $_POST['quantity'];
        $brand = $_POST['brand'];
        $description = $_POST['description'];

        $query->bind_param("ssdiss", $title, $category_id, $price, $qty, $brand, $description);
        $query->execute();

    }

    $this->app->flash('message', array('type' => 'success', 'text' => 'Product was created!'));
}else{
    $this->app->flash('message', array('type' => 'danger', 'response' => $response, 'text' => 'Product was not created!'));
}

$this->app->redirect('/tester/ebay_trading_api/products/new');

Next, we’ll define the addItem method in the Ebay class. Define 2 parameters: $store_settings and $item_data. Inside the method declare a variable called $boolean_value. This allows us to convert the integer value 0 to a string false and the integer value 1 to a string true. We need this because the API only accepts either true or false for boolean parameters.

Next, assign the uploads session item to a variable. If you remember from earlier, this session item is where we pushed the filenames of the images that the user uploaded. Next is the $baseupload_url, this contains the base URL in which all uploaded images can be found. We need this because the UploadSiteHostedPictures API method only accepts a URL for uploading to ebay. This also means that you need to have an actual server that’s accessible via public internet. The UploadSiteHostedPictures method only accepts a single URL at a time so we have to loop through all the images and supply the actual URL as the value for the ExternalPictureURL field. If the request is successful we just append the new image URL that’s returned to the $picture_details variable. This will be used as one of the arguments passed to the call for actually creating the product on eBay.

Next, we make the request for adding the product to eBay. This can be done via either the AddItem method or the VerifyAddItem method. The AddItem method is the one that you would want in production, since it adds the product to ebay. If there are any fees, those are also applied. VerifyAddItem on the other hand acts like a sandbox method, it doesn’t actually add the item on ebay. You can use it if you want to test the AddItem call. No fees are applied when you call it, but it lets you know how much of a fee will be applied or if the request would actually be successful. Note that you don’t need to use the sandbox version of the API in order to call the VerifyAddItem method. You can use it even on the live version of the API.

public function addItem($store_settings, $item_data){

  $boolean_value = array('false', 'true');

  $product_images = $_SESSION['uploads'];

  $baseupload_url = 'http://somewhere.com/uploads/';

  $picture_details = '';
  if(!empty($product_images)){
    foreach($product_images as $img){

      $requestBody = '<?xml version="1.0" encoding="utf-8"?>
      <UploadSiteHostedPicturesRequest xmlns="urn:ebay:apis:eBLBaseComponents">
        <RequesterCredentials>
          <eBayAuthToken>' . $this->user_token . '</eBayAuthToken>
        </RequesterCredentials>
        <ExternalPictureURL>' . $baseupload_url . '' . $img . '</ExternalPictureURL>
      </UploadSiteHostedPicturesRequest>';


      $response = $this->request('UploadSiteHostedPictures', $requestBody);
      
      if(!empty($response->Ack) && $response->Ack != 'Failure'){
        $uploaded_img = json_decode(json_encode($response->SiteHostedPictureDetails->PictureSetMember[3]->MemberURL), true);
        $picture_details .= '<PictureURL>' . $uploaded_img[0] . '</PictureURL>';
      }
    }   
  }
  
  $requestBody = '<?xml version="1.0" encoding="utf-8"?>
    <AddItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">
      <RequesterCredentials>
        <eBayAuthToken>' . $this->user_token . '</eBayAuthToken>
      </RequesterCredentials>
      <Item>
        <SellerProfiles> 
          <SellerPaymentProfile>
            <PaymentProfileID>' . $store_settings->payment_profile . '</PaymentProfileID>
          </SellerPaymentProfile>
          <SellerReturnProfile>
            <ReturnProfileID>' . $store_settings->return_profile . '</ReturnProfileID>
          </SellerReturnProfile>
          <SellerShippingProfile>
            <ShippingProfileID>' . $store_settings->shipping_profile . '</ShippingProfileID>
          </SellerShippingProfile>
        </SellerProfiles> 
        <OutOfStockControl>' . $store_settings->out_of_stock_control . '</OutOfStockControl>
        <GetItFast>' . $boolean_value[$store_settings->get_it_fast] . '</GetItFast>
        <CategoryBasedAttributesPrefill>' . $boolean_value[$store_settings->category_prefill] . '</CategoryBasedAttributesPrefill>
        <CategoryMappingAllowed>' . $boolean_value[$store_settings->category_mapping] . '</CategoryMappingAllowed>
        <ConditionID>' . $store_settings->condition_type . '</ConditionID>
        <Country>' . $store_settings->country_code_type . '</Country>
        <Currency>' . $store_settings->currency_code . '</Currency>
        <Description>' . $item_data['description'] . '</Description>
        <DispatchTimeMax>' . $store_settings->dispatch_time . '</DispatchTimeMax>
        <ListingDesigner>
          <OptimalPictureSize>' . $boolean_value[$store_settings->optimal_picturesize] . '</OptimalPictureSize>
        </ListingDesigner> 
        <ListingDuration>' . $store_settings->listing_duration . '</ListingDuration>
        <ListingType>' . $store_settings->listing_type . '</ListingType>
        <Location>' . $store_settings->item_location . '</Location>
        <PictureDetails>'
          . $picture_details . 
        '</PictureDetails>
        <PostalCode>' . $store_settings->postal_code . '</PostalCode>
        <PrimaryCategory>
          <CategoryID>' . $item_data['category_id'] . '</CategoryID>
        </PrimaryCategory>
        <Quantity>' . $item_data['quantity'] . '</Quantity>
        <SellerContactDetails>
          <CompanyName>' . $store_settings->store_name . '</CompanyName>
          <County>' . $store_settings->county . '</County>
          <Street>' . $store_settings->street . '</Street>
        </SellerContactDetails>
        <Site>' . $store_settings->ebay_website . '</Site>
        <StartPrice currencyID="' . $store_settings->currency_code . '">' . $item_data['price'] . '</StartPrice>
        <Title>' . $item_data['title'] . '</Title>
        <ShippingDetails>
        <ShippingServiceOptions>
          <ShippingServicePriority>' . $store_settings->shippingservice_priority . '</ShippingServicePriority>
          <ShippingService>' . $store_settings->shipping_service . '</ShippingService>
          <ShippingServiceCost currencyID="' . $store_settings->currency_code . '">' . $store_settings->shippingservice_cost . '</ShippingServiceCost>
          <ShippingServiceAdditionalCost currencyID="' . $store_settings->currency_code . '">' . $store_settings->shippingservice_additionalcost . '</ShippingServiceAdditionalCost>
        </ShippingServiceOptions>
        </ShippingDetails>
      </Item>
    </AddItemRequest>';

  $response = $this->request('AddItem', $requestBody);

  return $response; 
  
}

To make things clearer, here’s a breakdown of the parameters we passed to the AddItem request. Here we’re passing in the seller profiles. The only requirement for each seller profile is the profile ID. We already got those earlier when we fetched the store settings, so we simply get them from the database.

<SellerProfiles> 
  <SellerPaymentProfile>
    <PaymentProfileID>' . $store_settings->payment_profile . '</PaymentProfileID>
  </SellerPaymentProfile>
  <SellerReturnProfile>
    <ReturnProfileID>' . $store_settings->return_profile . '</ReturnProfileID>
  </SellerReturnProfile>
  <SellerShippingProfile>
    <ShippingProfileID>' . $store_settings->shipping_profile . '</ShippingProfileID>
  </SellerShippingProfile>
</SellerProfiles>

OutOfStockControl is a boolean value for specifying whether to keep the listing alive after it reaches a quantity of 0. Setting this to true excludes the listing from search results and from being viewed.

<OutOfStockControl>' . $store_settings->out_of_stock_control . '</OutOfStockControl>

GetItFast is a boolean value for specifying whether the “get it fast” shipping is enabled or not.

<GetItFast>' . $boolean_value[$store_settings->get_it_fast] . '</GetItFast>

CategoryBasedAttributesPrefill is a boolean value for specifying whether to prefill some of the item data based on the selected category.

<CategoryBasedAttributesPrefill>' . $boolean_value[$store_settings->category_prefill] . '</CategoryBasedAttributesPrefill>

CategoryMappingAllowed is a boolean value for specifying whether eBay will look up the current category ID that is mapped to the same category and use the new Category ID for the listing or not.

<CategoryMappingAllowed>' . $boolean_value[$store_settings->category_mapping] . '</CategoryMappingAllowed>

ConditionID allows you to specify the item condition. eBay has assigned numeric values to every possible item condition. Check the table on this page.

<ConditionID>' . $store_settings->condition_type . '</ConditionID>

Country allows you to specify the country in which the item is located. You can check out a list of country codes and their corresponding country from this page.

<Country>' . $store_settings->country_code_type . '</Country>

Currency allows you to specify the currency in which the price of the product is expressed.

<Currency>' . $store_settings->currency_code . '</Currency>

Description is the description of the item. You can also pass in HTML to this field.

<Description>' . $item_data['description'] . '</Description>

DispatchTimeMax is the max number of days in which the item will be dispatched or mailed to the customer. Specifying 0 means that the item is mailed to the customer as soon as the order is received.

<DispatchTimeMax>' . $store_settings->dispatch_time . '</DispatchTimeMax>

OptimalPictureSize is a boolean value for specifying whether the the product image will be enlarged to fit the description of the item or not.

<ListingDesigner>
  <OptimalPictureSize>' . $boolean_value[$store_settings->optimal_picturesize] . '</OptimalPictureSize>
</ListingDesigner>

ListingDuration allows you to specify the number of days you want the listing to be active. Valid values can be found on this page.

<ListingDuration>' . $store_settings->listing_duration . '</ListingDuration>

ListingType allows you to specify the type of listing. Valid values can be found on this page. The usual value for this field is either Auction or FixedPriceItem.

<ListingType>' . $store_settings->listing_type . '</ListingType>

Location is the location of the item. This is a conditional field; if you don’t know the value for the PostalCode then you can just specify the value for this field.

<Location>' . $store_settings->item_location . '</Location>

PictureDetails is where we put in the URL’s of the product images that we have uploaded to eBay.

<PictureDetails>'
 . $picture_details . 
'</PictureDetails>

PostalCode is the postal code of the area where the item is located. You can use the Location or this field to specify the location of the item.

<PostalCode>' . $store_settings->postal_code . '</PostalCode>

CategoryID is the ID of the main category of the item.

<PrimaryCategory>
  <CategoryID>' . $item_data['category_id'] . '</CategoryID>
</PrimaryCategory>

Quantity is an integer value of how many units of a specific item you have on your inventory.

<Quantity>' . $item_data['quantity'] . '</Quantity>

SellerContactDetails is where you specify the contact details of the seller. This is an optional field, it uses the seller information by default. But you can use this to override the settings.

<SellerContactDetails>
  <CompanyName>' . $store_settings->store_name . '</CompanyName>
  <County>' . $store_settings->county . '</County>
  <Street>' . $store_settings->street . '</Street>
</SellerContactDetails>

Site is the ID of the eBay website where the product is listed. Examples include US for United States, and UK for United Kingdom. A list of valid values for this field can be found on this page.

<Site>' . $store_settings->ebay_website . '</Site>

StartPrice is the starting price of the item when it is listed for the first time, or when revised or relisted.

<StartPrice currencyID="' . $store_settings->currency_code . '">' . $item_data['price'] . '</StartPrice>

Title is the title of the product.

<Title>' . $item_data['title'] . '</Title>

ShippingDetails is where you specify the shipping details for the product, such as the shipping service to be used, and additional costs if any.

<ShippingDetails>
  <ShippingServiceOptions>
    <ShippingServicePriority>' . $store_settings->shippingservice_priority . '</ShippingServicePriority>
      <ShippingService>' . $store_settings->shipping_service . '</ShippingService>
      <ShippingServiceCost currencyID="' . $store_settings->currency_code . '">' . $store_settings->shippingservice_cost . '</ShippingServiceCost>
      <ShippingServiceAdditionalCost currencyID="' . $store_settings->currency_code . '">' . $store_settings->shippingservice_additionalcost . '</ShippingServiceAdditionalCost>
  </ShippingServiceOptions>
</ShippingDetails>

Conclusion

That’s it! In this tutorial we went through eBay’s Trading API. We have learned that we can talk to their API by acquiring a token for the user. We also walk through fetching the user settings, uploading images and adding products using the API. But that’s not all you can do with Ebay’s Trading API. It’s a pretty huge API and almost anything that you can think of that you can do with eBay with regards to selling products, you can also do with the API. So be sure to check the docs if you’re curious. You can check out the source code of the project we’ve built in this github repository.

Feedback appreciated!

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in PHP, once a week, for free.