Search code examples
perlebay-api

How do I use ItemFilters with eBay::API::Simple::Finding?


I am playing with getting sold items from ebay using eBay::API::Simple::Finding and I want to use ItemFilters but I can't see where they go. In particular I am looking to use the item filters

(itemFilter.name = SoldItemsOnly, itemFilter.value = true)
and
(itemFilter.name = Condition, itemFilter.value = Used)

I tried just including directly with the following here:

keywords => '"princess cut", "diamond ring", -"14k*"', 
Condition => 'Sold',
SoldItemsOnly => 'true', 
sortOrder => 'PricePlusShippingHighest'

I have been on it quite a while and whilst I am sure it is somehow quite straight forward, I just can't seem to get it

use eBay::API::Simple::Finding;

my $api = eBay::API::Simple::Finding->new( {
   appid   => 'APIKEY',
   siteid  => 'EBAY-AU',
} );

$api->execute( 
    'findCompletedItems', { 
    keywords => '"princess cut", "diamond ring", -"14k*"',  
    sortOrder => 'PricePlusShippingHighest',
    } 
);

if ( $api->has_error() ) {
   die "Call Failed:" . $api->errors_as_string();
}

my $dom  = $api->response_dom();
my $hash = $api->response_hash();

Any help is very appreciated,

As for what I am seeing? The sort is working, the search by keywords is working, but the itemfilters are not working, so it is returning new & used items that have completed, whether sold or unsold


Solution

  • Reading the eBay API docs about findCompletedItems shows that you need to use child elements for ItemFilters. There is a sample that shows this nicely (link).

    <?xml version="1.0" encoding="UTF-8"?>
    <findCompletedItemsRequest xmlns="http://www.ebay.com/marketplace/search/v1/services">
       <keywords>Garmin nuvi 1300 Automotive GPS Receiver</keywords>
       <categoryId>156955</categoryId>
       <itemFilter>
          <name>Condition</name>
          <value>3000</value>
       </itemFilter>
       <itemFilter>
          <name>FreeShippingOnly</name>
          <value>true</value>
       </itemFilter>
       <itemFilter>
          <name>SoldItemsOnly</name>
          <value>true</value>
       </itemFilter>
       <sortOrder>PricePlusShippingLowest</sortOrder>
       <paginationInput>
          <entriesPerPage>2</entriesPerPage>
          <pageNumber>1</pageNumber>
       </paginationInput>
    </findCompletedItemsRequest>
    

    Looking at the source code of the eBay::API::Simple::Finding module we can see that it uses XML::Simple to construct requests. While in general XML::Simple is discouraged, we will have to work with it.

    Taking a deeper look at the docs for the ItemFilter shows that we can provide one <itemFilter> block per filter. That implies that multiple ones are treated as AND automatically.

    To make a single item with the way XML::Simple get set up in the API module, we just need a hashref.

    {
        itemFilter => {
            name => 'Condition',
            value => 3000,
        },
    }
    

    will become

    <itemFilter>
      <name>Condition</name>
      <value>3000</value>
    </itemFilter>
    

    To get several, we need an array reference behind the itemFilter key.

    {
        itemFilter => [
            {
                name => 'Condition',
                value => 3000,
            },
            {
                name => 'FreeShippingOnly',
                value => 'true',
            },
        ],
    }
    

    This produces this XML.

    <itemFilter>
      <name>Condition</name>
      <value>3000</value>
    </itemFilter>
    <itemFilter>
      <name>FreeShippingOnly</name>
      <value>true</value>
    </itemFilter>
    

    So far so good. We can easily hack that into the API module call. Instead of executing the call directly, I have prepared it, and then called the private method _get_request_body, which uses XML::Simple to form and return the request body string. That's neat to check if the request will look ok. I figured that out by reading the code, starting at the one I lined above, and working my way towards the base class, which provides execute.

    use eBay::API::Simple::Finding;
    
    my $api = eBay::API::Simple::Finding->new( {
       appid   => 'APIKEY',
       siteid  => 'EBAY-AU',
    } );
    
    $api->prepare(
        'findCompletedItems',
        {
            keywords   => '"princess cut", "diamond ring", -"14k*"',
            sortOrder  => 'PricePlusShippingHighest',
            itemFilter => [
                {
                    name  => 'SoldItemsOnly',
                    value => 'true',
                },
                {
                    name  => 'Condition',
                    value => 'Used',
                },
            ],
        }
    );
    
    print $api->_get_request_body;
    

    Here's the XML that comes out.

    <?xml version='1.0' encoding='utf-8'?>
    <findCompletedItemsRequest xmlns="http://www.ebay.com/marketplace/search/v1/services">
      <itemFilter>
        <name>SoldItemsOnly</name>
        <value>true</value>
      </itemFilter>
      <itemFilter>
        <name>Condition</name>
        <value>Used</value>
      </itemFilter>
      <keywords>&quot;princess cut&quot;, &quot;diamond ring&quot;, -&quot;14k*&quot;</keywords>
      <sortOrder>PricePlusShippingHighest</sortOrder>
    </findCompletedItemsRequest>
    

    It doesn't matter that it' not indented nicely. It is clear that the filters are there.

    Since I don't have an API key I cannot run this myself, but I am pretty sure it's going to work.