Code Monkey home page Code Monkey logo

ebay-api's Introduction

eBay Node API in TypeScript with Browser support

Build Status codecov

GitHub npm version npm

This eBay API implements both Traditional (xml) and the RESTful eBay API. It supports client credentials grant and authorization code grant (Auth'N'Auth, OAuth2 and IAF). Digital Signature is supported too.

eBay Docs

Changelog

  • v9.1.0 is the latest release.
  • See here for the full changelog.

Implementation status

RESTful API

API Implemented
Buy API ✔ Browse API v1.10.0
✔ Deal API v1.3.0
✔ Feed API v1.3.1
✔ Marketing API v1_beta.1.0
✔ Offer API v1_beta.0.0
✔ Order API v1_beta.20.0
✔ Marketplace Insights API v1_beta.2.2
Commerce API ✔ Catalog API v1_beta.3.1
✔ Charity API v1.2.0
✔ Identity API v1.0.0
✔ Notification API v1.2.0
✔ Taxonomy API v1.0.0
✔ Translation API v1_beta.1.4
✔ Media API v1_beta.1.0
Developer API ✔ Analytics API
Post Order API ✔ Cancellation API
✔ Case Management API
✔ Inquiry API
✔ Return API
Sell API ✔ Account API v1.9.0
✔ Analytics API v1.3.0
✔ Compliance API v1.4.1
✔ Feed API v1.3.1
✔ Finance API v1.9.0
✔ Fulfillment API v1.19.10
✔ Inventory API v1.14.0
✔ Listing API v1_beta.2.1
✔ Logistics API v1_beta.0.0
✔ Marketing API v1.17.0
✔ Metadata API v1.7.1
✔ Negotiation API v1.1.0
✔ Recommendation API v1.1.0

Traditional API

API Implemented
Finding API
Shopping API
Merchandising API
Trading API
Client Alerts API
Feedback API

Install

npm install ebay-api 
yarn add ebay-api

🚀 Usage & Quick start

Sign up for an API key here: Developer Account. Checkout API examples.

NodeJS

import eBayApi from 'ebay-api';
// or:
// const eBayApi = require('ebay-api')

const eBay = new eBayApi({
  appId: '-- also called Client ID --',
  certId: '-- also called Client Secret --',
  sandbox: false
});

const item = await eBay.buy.browse.getItem('v1|254188828753|0');
console.log(JSON.stringify(item, null, 2));

Detailed configuration example

import eBayApi from 'ebay-api';

const eBay = new eBayApi({
  appId: '-- also called Client ID --',
  certId: '-- also called Client Secret --',
  sandbox: false,

  siteId: eBayApi.SiteId.EBAY_US, // required for traditional APIs, see https://developer.ebay.com/DevZone/merchandising/docs/Concepts/SiteIDToGlobalID.html

  marketplaceId: eBayApi.MarketplaceId.EBAY_US, // default. required for RESTful APIs
  acceptLanguage: eBayApi.Locale.en_US, // default
  contentLanguage: eBayApi.Locale.en_US, // default.

  // optional parameters, should be omitted if not used
  devId: '-- devId --', // required for traditional Trading API
  ruName: '-- eBay Redirect URL name --', // 'RuName' (eBay Redirect URL name) required for authorization code grant

  authToken: '--  Auth\'n\'Auth for traditional API (used by trading) --', // can be set to use traditional API without code grant
});

Browser

Check out live example: https://hendt.github.io/ebay-api/. Because of the eBay CORS problems a Proxy server is required to use the API in the Browser.

For testing purpose you can use https://ebay.hendt.workers.dev/ url as proxy. You can also set up your own Proxy server. We have added a example for cloudfront workers: https://github.com/hendt/ebay-api/blob/master/proxy/worker.js

Or use [https://github.com/Rob--W/cors-anywhere](CORS Anywhere is a NodeJS proxy) (works very well with heroku.com).

ESM

<script type="module">
    import eBayApi from 'https://cdn.jsdelivr.net/npm/ebay-api@latest/dist/ebay-api.min.mjs';
    // or 
    import eBayApiEsm from 'https://esm.sh/ebay-api';
</script>

UMD

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ebay-api@latest/lib/ebay-api.min.js"></script>
<script>
    const eBay = new eBayApi({
        appId: 'appId',
        certId: 'certId',
        sandbox: false
    });

    // eBay.req.instance is AxiosInstance per default
    eBay.req.instance.interceptors.request.use((request) => {
        // Add Proxy
        request.url = 'https://ebay.hendt.workers.dev/' + request.url;
        return request;
    });

    eBay.buy.browse.getItem('v1|254188828753|0').then(item => {
        console.log(JSON.stringify(item, null, 2));
    }).catch(e => {
        console.error(e);
    });
</script>

🔧 eBayApi Config

The first (required) parameter in eBayApi instance takes an object with following properties:

Name Occurrence Description
appId Required App ID (Client ID) from Application Keys.
certId Required Cert ID (Client Secret) from Application Keys.
devId Conditionally The Dev Id from Application Keys.
sandbox Required
Default: false
If true, the Sandbox Environment will be used.
ruName Conditionally The redirect_url value. More info.
autoRefreshToken Required
Default: true
Auto refresh the token if it's expired.
siteId
Traditional
Required
Default: SiteId.EBAY_US
eBay site to which you want to send the request (Trading API, Shopping API).
authToken
Traditional
Optional The Auth'N'Auth token. The traditional authentication and authorization technology used by the eBay APIs.
marketplaceId
RESTful
Required
Default: MarketplaceId.EBAY_US
Docs REST HTTP Header. X-EBAY-C-MARKETPLACE-ID identifies the user's business context and is specified using a marketplace ID value. Note that this header does not indicate a language preference or consumer location.
scope
RESTful
Conditionally
Default:
['https://api.ebay.com/oauth/api_scope']
The scopes assigned to your application allow access to different API resources and functionality.
endUserCtx
RESTful
Conditionally recommended
RESTful
Docs X-EBAY_C_ENDUSERCTX provides various types of information associated with the request.
contentLanguage
RESTful
Conditionally required
Default: Locale.en_US
DocsContent-Language indicates the locale preferred by the client for the response.
acceptLanguage
RESTful
Optional
Default: Locale.en_US
Docs Accept-Language indicates the natural language the client prefers for the response. This specifies the language the client wants to use when the field values provided in the request body are displayed to consumers.

Load config from environment

Use eBayApi.fromEnv() to load data from environment variables.

Name Value
appId process.env.EBAY_APP_ID
certId process.env.EBAY_CERT_ID
devId process.env.EBAY_DEV_ID
authToken process.env.EBAY_AUTH_TOKEN
siteId process.env.EBAY_SITE_ID
marketplaceId process.env.EBAY_MARKETPLACE_ID
ruName process.env.EBAY_RU_NAME
sandbox process.env.EBAY_SANDBOX === 'true'

🐞 Debug

To see node debug logs use DEBUG=ebay:* environment variable.

🔑 Access token types

See the full Documentation here.

Client credentials grant flow mints a new Application access token. Authorization code grant flow mints a new User access token.

User access token (authorization code grant flow)

👉 Recommended for all API Calls.

You must employ a User token to call any interface that accesses or modifies data that is owned by the user (such as user information and account data). To get a User token, the users of your app must grant your application the permissions it needs to act upon their behalf. This process is called user consent. With the user consent flow, each User token contains the set of scopes for which the user has granted their permission (eBay Token Types).

Application access token (client credentials grant flow)

👉 Recommended for API calls that will only request application data (GET method, and it's also restricted).

Application tokens are general-use tokens that give access to interfaces that return application data. For example, many GET requests require only an Application token for authorization. (eBay Token Types)

If no other token is set, this token will be obtained automatically in the process of calling an RESTful API.

Auth'N'Auth

👉 The "old" way. Only works with Traditional API. Checkout the Auth'N'Auth example.

You can also generate the token on eBay developer page and use it directly (see Detailed configuration example).

OAuth2: Exchanging the authorization code for a User access token

eBay Docs

import eBayApi from 'ebay-api';

// 1. Create new eBayApi instance and set the scope.
const eBay = eBayApi.fromEnv();

eBay.OAuth2.setScope([
  'https://api.ebay.com/oauth/api_scope',
  'https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly',
  'https://api.ebay.com/oauth/api_scope/sell.fulfillment'
]);

// 2. Generate and open Url and Grant Access
const url = eBay.OAuth2.generateAuthUrl();
console.log('Open URL', url);

After you granted success, eBay will redirect you to your 'Auth accepted URL' and add a query parameter code

Express example

This is how it would look like if you use express:

import eBayApi from 'ebay-api';


// This is your RUName endpoint like https://your-ebay.app/success
app.get('/success', async function (req, res) {
  // 3. Get the parameter code that is placed as query parameter in redirected page
  const code = req.query.code; // this is provided from eBay
  const eBay = eBayApi.fromEnv(); // or use new eBayApi()

  try {
    const token = await eBay.OAuth2.getToken(code);
    eBay.OAuth2.setCredentials(token);
    // store this token e.g. to a session
    req.session.token = token

    // 5. Start using the API
    const orders = await eBay.sell.fulfillment.getOrders()
    res.send(orders);
  } catch (error) {
    console.error(error)
    res.sendStatus(400)
  }
});

If token is already in session:

import eBayApi from 'ebay-api';

app.get('/orders/:id', async function (req, res) {
  const id = req.params.id;
  const eBay = eBayApi.fromEnv(); // or use new eBayApi(...)
  const token = req.session.token;
  if (!token) {
    return res.sendStatus(403);
  }

  eBay.OAuth2.setCredentials(token);

  // If token get's refreshed
  eBay.OAuth2.on('refreshAuthToken', (token) => {
    req.session.token = token;
  });

  try {
    // 5. Start using the API
    const order = await eBay.sell.fulfillment.getOrder(id);
    res.send(order);
  } catch (error) {
    console.error(error)
    res.sendStatus(400)
  }
});

Digital Signature

Signatures are required when the call is made for EU- or UK-domiciled sellers, and only for the following APIs/methods:

  • All methods in the Finances API -> (eBay.finances.XXX.sign.YYY())
  • issueRefund in the Fulfillment API -> (eBay.sell.fulfillment.sign.issueRefund())
  • GetAccount in the Trading API -> (eBay.trading.GetAccount(null, { sign: true })))
  • The following methods in the Post-Order API:
    • Issue Inquiry Refund -> (eBay.postOrder.inquiry.sign.issueInquiryRefund())
    • Issue case refund -> (eBay.postOrder.inquiry.sign.issueCaseRefund())
    • Issue return refund -> (eBay.postOrder.inquiry.sign.issueReturnRefund())
    • Process Return Request -> (eBay.postOrder.inquiry.sign.processReturnRequest())
    • Create Cancellation Request -> (eBay.postOrder.inquiry.sign.createCancellation())
    • Approve Cancellation Request -> (eBay.postOrder.inquiry.sign.approveCancellationRequest())

How to use Digital Signature

// 1. Create singning key and save it appropriatly
const signingKey = await eBay.developer.keyManagement.createSigningKey('ED25519');
// 2. Set the signature
eBay.setSignature(signingKey)
// or in constructor
eBay = new eBayApi({
   appId: '...',
   certId: '...',
   signature: {
      jwe: signingKey.jwe,
      privateKey: signingKey.privateKey
   }
});
// 3. Use the 'sign' keyword in Restful API
const summary = await eBay.sell.finances.sign.getSellerFundsSummary();
// 3. Or the 'sign' parameter in traditional API
const account = await eBay.trading.GetAccount(null, {sign: true});

RESTful API

How to set the Scope

const eBay = new eBayApi({
  // ...
  scope: ['https://api.ebay.com/oauth/api_scope']
});

// Or:
eBay.OAuth2.setScope([
  'https://api.ebay.com/oauth/api_scope',
  'https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly',
  'https://api.ebay.com/oauth/api_scope/sell.fulfillment'
]);

Use apix.ebay.com or apiz.ebay.com (beta) endpoints

For some APIs, eBay use a apix/apiz subdomain. To use these subdomains you can use .apix/.apiz before the api call like this:

  eBay.buy.browse.apix.getItem() // now it will use https://apix.ebay.com
eBay.buy.browse.apiz.getItem() // now it will use https://apiz.ebay.com

In any case eBay adds a new subdomain, it's also possible to configure whatever you want:

  eBay.buy.browse.api({subdomain: 'apiy'}).getItem() // now it will use https://apiy.ebay.com

Return raw RESTful API response

  eBay.buy.browse.api({
  returnResponse: true, // return the response instead of data
}).getItem();

How to refresh the token

If autoRefreshToken is set to true (default value) the token will be automatically refreshed when eBay response with invalid access token error.

Use Event Emitter to get the token when it gets successfully refreshed.

eBay.OAuth2.on('refreshAuthToken', (token) => {
  console.log(token)
  // Store this token in DB
});

// for client token
eBay.OAuth2.on('refreshClientToken', (token) => {
  console.log(token)
  // Store this token in DB
});

To manual refresh the auth token use eBay.OAuth2.refreshAuthToken() and for the client token use eBay.OAuth2.refreshClientToken(). Keep in mind that you need the 'refresh_token' value set.

const token = await eBay.OAuth2.refreshToken();
// will refresh Auth Token if set, otherwise the client token if set.

Additional request headers

Sometimes you want to add additional headers to the request like a GLOBAL-ID X-EBAY-SOA-GLOBAL-ID. You have multiple options to do this.

RESTful API headers

  const eBay = new eBayApi();

eBay.buy.browse.api({
  headers: {
    'X-EBAY-SOA-GLOBAL-ID': 'EBAY-DE'
  }
}).getItem('v1|382282567190|651094235351').then((item) => {
  console.log(item)
})

Traditional API headers

You can pass headers directly in the method call in the second parameter:

eBay.trading.AddFixedPriceItem({
  Item: {
    Title: 'title',
    Description: {
      __cdata: '<div>test</div>'
    }
  }
}, {
  headers: {
    'X-EBAY-SOA-GLOBAL-ID': 'EBAY-DE'
  }
})

Low level: use the Axios interceptor to manipulate the request

import eBayApi from 'ebay-api';

const eBay = new eBayApi(/* {  your config here } */);

eBay.req.instance.interceptors.request.use((request) => {
  // Add Header
  request.headers['X-EBAY-SOA-GLOBAL-ID'] = 'EBAY-DE';
  return request;
})

Handle JSON GZIP response e.g fetchItemAspects

You need a decompress library installed like zlib.

npm install zlib # or yarn add zlib
import eBayApi from 'ebay-api';
import zlib from 'zlib';

const toString = (data) => new Promise((resolve) => {
  zlib.gunzip(data, (err, output) => {
    if (err) throw err;
    resolve(output.toString());
  });
});

const eBay = new eBayApi(/* {  your config here } */);

try {
  const data = await eBay.commerce.taxonomy.fetchItemAspects(/* categoryTreeId */);
  const result = await toString(data);

  console.log(result)
} catch (error) {
  console.error(error);
}

Handling errors

import eBayApi from 'ebay-api';
import { EBayApiError } from 'ebay-api/lib/errors';

const eBay = new eBayApi(/* {  your config here } */);

try {
  const result = await eBay.trading.GetItem({
    ItemID: 'itemId',
  });
  console.log(result);
} catch (error) {
  if (error instanceof EBayApiError && error.errorCode === 17) {
    // Item not found
  } else {
    throw error;
  }
  
  // in error there is also the field "meta" with the response
  if (error instanceof EBayApiError && error.meta?.res?.status === 404) {
    // not found
    
    // The first error
    console.log(error?.firstError);
  }
  
  
}

The errorCode is extracted from the first error in the API response.

Controlling Traditional XML request and response

The second parameter in the traditional API has the following options:

export type Options = {
  raw?: boolean // return raw XML
  parseOptions?: X2jOptions // https://github.com/NaturalIntelligence/fast-xml-parser
  xmlBuilderOptions?: XmlBuilderOptions // https://github.com/NaturalIntelligence/fast-xml-parser
  useIaf?: boolean // use IAF in header instead of Bearer
  headers?: Headers // additional Headers (key, value)
  hook?: (xml) => BodyHeaders // hook into the request to modify the body and headers
};

Fast XML is used to parse the XML. You can pass the parse option to parseOptions parameter.

Parse JSON Array

eBay.trading.SetNotificationPreferences({
  UserDeliveryPreferenceArray: [{
    NotificationEnable: {
      EventType: 'ItemListed',
      EventEnable: 'Enable',
    }
  }, {
    NotificationEnable: {
      EventType: 'ItemSold',
      EventEnable: 'Enable',
    },
  }],
}, { xmlBuilderOptions: { oneListGroup: true }})

Will produce:

<UserDeliveryPreferenceArray>
  <NotificationEnable>
    <EventType>ItemListed</EventType>
    <EventEnable>Enable</EventEnable>
  </NotificationEnable>
  <NotificationEnable>
    <EventType>ItemSold</EventType>
    <EventEnable>Enable</EventEnable>
  </NotificationEnable>
</UserDeliveryPreferenceArray>

Examples

Trading - AddFixedPriceItem (CDATA)

You can submit your description using CDATA if you want to use HTML or XML.

eBay.trading.AddFixedPriceItem({
  Item: {
    Title: 'title',
    Description: {
      __cdata: '<div>test</div>'
    }
  }
})

Trading - ReviseFixedPriceItem (Update the price of an item)

eBay.trading.ReviseFixedPriceItem({
  Item: {
    ItemID: 'itemId',
    StartPrice: 'startPrice'
  }
})

Buy - getItem

eBay.buy.browse.getItem('v1|382282567190|651094235351').then(a => {
  console.log(a);
}).catch(e => {
  console.log(e)
});

Post-Order - getReturn

eBay.postOrder.return.getReturn('5132021997').then(a => {
  console.log(a);
}).catch(e => {
  console.log(e)
});

Finding - findItemsByProduct (use XML attributes and value)

eBay.finding.findItemsByProduct({
  productId: {
    '@_type': 'ReferenceID',
    '#value': '53039031'
  }
})

// will produce:
// <productId type="ReferenceID">53039031</productId>

Finding - findItemsIneBayStores

eBay.finding.findItemsIneBayStores({
  storeName: 'HENDT'
}, {raw: true}).then(result => {
  // Return raw XML
  console.log(result);
});

Finding - findItemsAdvanced (findItemsByKeywords)

eBay.finding.findItemsAdvanced({
  itemFilter: [{
    name: 'Seller',
    value: 'hendt_de'
  }],
  keywords: 'katze'
}).then(result => {
  console.log(result);
});

Trading - GetMyeBaySelling

eBay.trading.GetMyeBaySelling({
  SoldList: {
    Include: true,
    Pagination: {
      EntriesPerPage: 20,
      PageNumber: 1
    }
  }
}).then(data => {
  console.log(data.results)
});

FAQ

  1. Do I need the eBay OAuth Client dependency?

No. This library has already all authentication implemented and support also auto refreshing token.

  1. What does IAF mean?

IAF stands for IDENTITY ASSERTION FRAMEWORK. The traditional API supports IAF. That means you can use the OAuth2 token with the traditional APIs.

  1. Is it possible to Upload Pictures directly to EPS?

Yes. Checkout the Browser example and Node Example here.

  1. itemAffiliateWebUrl is missing in eBay.buy.browse.search call You have to set endUserCtx.

Contribution

Check here

Supported By

hendt.de
rootle.de

📝 License

MIT.

ebay-api's People

Contributors

bennyk8y avatar borduhh avatar dantio avatar dependabot[bot] avatar derjones avatar iamsr avatar juanbits avatar k3vchan avatar namanattri avatar nrodriguez avatar olliechick avatar spidgorny avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ebay-api's Issues

Using HTML in Description of AddFixedPriceItem results in Schema XML request error

I've got the API creating new eBay listings and everything works fine when I just include text as the description. For example, this works great:

Screen Shot 2020-11-10 at 12 53 18 PM

But when I add any html tags, such as the following:

Screen Shot 2020-11-10 at 12 52 49 PM

...I get this error:

"Schema XML request error: SimpleDeserializer encountered a child element, which is NOT expected, in something it was trying to deserialize"

Screen Shot 2020-11-10 at 12 53 59 PM

Re-authorizing

Thanks so much for this work - it is excellent. When I am developing with your ebay-api (using it in a docker container) I find myself having to re-authorise at eBay (eBay.OAuth2.generateAuthUrl()) every time I take the container down. I could persist the tokens so I can reuse them without going back to eBay. I get an access token (eBay.OAuth2.getToken) when I get this token I could persist it and re-use it I think.
My question is can I persist a token (I am usually rerunning the docker container within 30 minutes)? What token would I persist and what method in your api would I call with this token to maintain/re-establish the connection? Thanks again its the flow that is confusing me.
Gary

Having Trouble Listing Images

Hi, I successfully listed some items using your library but can't seem to get the pictures to list.

My images are being sent this way:

    PictureDetails: [
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object]
    ],

Each of the "Object" items looks like this:
'https://imageurl.....'

So that the array appears like this:

pictureURLs: [
   'https://imageurl.....jpeg',
   'https://imageurl.....jpeg',
   'https://imageurl.....jpeg',
   'https://imageurl.....jpeg'
 ]

What is the correct way to send pictures to ebay when I list items though your library?

How to authroize the client?

There are examples on how to refresh the client and oauth tokens and and example to get an oauth token. I'm trying to simply use the API from a client and am struggling to understand how to authenticate calls without having to constantly open a new tab and copy in the code.

Request header field authorization is not allowed by Access-Control-Allow-Headers AND Accept-Encoding error

Hi,

im triyng to connect to the AOI but I get alwasy this issue:

Access to XMLHttpRequest at 'https://api.sandbox.ebay.com/identity/v1/oauth2/token' from origin 'http://localhost:8100' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

Here is my code:

const eBayApi = require('@hendt/ebay-api')

const eBay = new eBayApi({
  appId: 'xxxxxxxxx',
  certId: 'xxxxxxxxx',
  devId: 'xxxxxxxx',
  sandbox: true,
  siteId: eBayApi.SiteId.EBAY_DE,
  marketplaceId:  eBayApi.MarketplaceId.EBAY_DE,
  acceptLanguage: eBayApi.Locale.en_DE, 
  contentLanguage: eBayApi.ContentLanguage.en_DE, 
});

const item = await eBay.buy.browse.getItem('v1|254188828753|0');
console.log(JSON.stringify(item, null, 2));

image

How I can solve this problem?

The warning reply from UploadSiteHostedPictures is treated as an outright error.

According to the image guidelines on eBay:

If your image is less than 1,000 pixels (width + height in pixels), a warning is provided but the picture is not rejected.

However, in your handleEBayJsonResponse function, you're not checking the Ack property of the response, only checking that the Errors property is not null. Since the warning message from eBay comes in the Errors property, your code detects that and then throws your own EbayApiError, so the original response never gets through and I do not get a chance to see the still valid SiteHostedPictureDetails response:

Screen Shot 2021-10-11 at 3 18 48 PM

Is there any way to get those warnings handled as warnings and allowing those responses through, instead of handling them as outright errors and throwing EbayApiErrors?

How do you call createPaymentPolicy properly through hendt / ebay-api?

I can successfully create payment policies directly but I want to use your library to do so.

My code (which returns 404 error):

exports.createPaymentPolicy = async ( req, res ) => {
  try {
    let user = req.body.user 
    let _user = await User.findById({_id: user})
    eBay.auth.oAuth2.setCredentials(_user.token[0])
    let PaymentPolicyRequest = `{
      "categoryTypes": [     
       {     
        "default": false,     
        "name": "ALL_EXCLUDING_MOTORS_VEHICLES"     
       }     
      ],  
       "paymentMethods": [ ]
      },     
      "description": "Created from API call.",
      "immediatePay": true,     
      "marketplaceId": "EBAY_US",     
      "name": "testPayments_${_user.firstName}",
     }     
     `
    let result = await eBay.sell.account.createPaymentPolicy( PaymentPolicyRequest )
    console.log( `result...`, result ) 
    res.json( result )
  } catch ( e ) { console.log( `Got an error in createPaymentPolicy...`, e ); res.json( { error: e } ) }
}

I constantly get a 404 error when running this. What is the correct way to make this call?

specifying url params in fulfilment.getorders

How do I specify multiple url params?

Like this example, using filter and limit in getOrders()

function getOrders(orderId) {
    if (orderId) {
      return eBay.sell.fulfillment.getOrder(orderId);
    } else {
      return eBay.sell.fulfillment.getOrders(
        "?filter=orderfulfillmentstatus:{NOT_STARTED|IN_PROGRESS}?limit=5"
      );
    }
  }

thanks!!!

Restrict/Update Typescript Types

Saw that in several instances, any is used when I believe the type should be known.

For example:
/src/api/resetful/index.ts

    private async doRequest(
        method: keyof ILimitedRequest,
        url: string,
        config: any,
        data?: any
    ): Promise<any> {
        ...
    }

Could be restricted to:

    private async doRequest(
        method: keyof ILimitedRequest,
        url: string,
        config: AxiosRequestConfig,
        data?: {[key: string]: any}
    ): Promise<any> {
        ...
    }

Which would limit the parameters being passed in and make the program that much safer.

If this makes sense and you agree, I could take a whack at it this weekend.

How do you properly call getPrivileges? Got error: TypeError: eBay.sell.getPrivileges is not a function

Hi,

I want to know the seller limits for an account so I tried to call getPrivileges but got this error:
Got error: TypeError: eBay.sell.getPrivileges is not a function

My code:

exports.getSellerLimits = async (req, res) => {  
  let {        
    ebayAuthToken,
    } = req.body


    eBay.auth.oAuth2.setScope([
      'https://api.ebay.com/oauth/api_scope',
      'https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly',
      'https://api.ebay.com/oauth/api_scope/sell.fulfillment',
      'https://api.ebay.com/oauth/api_scope/sell.account',
      'https://api.ebay.com/oauth/api_scope/sell.account.readonly'
  ]);
    
    eBay.auth.oAuth2.setCredentials(ebayAuthToken);
  
    try {
    let result = await eBay.sell.getPrivileges()

    console.log('result...')
    console.log(result)
    res.json(result)

    }
    catch(e) {
      console.log(`Got error: `, e)
      res.json({error: e})
    }
    

}

How do you make this call?

How do you properly call refreshToken() to obtain a new token?

Hi, I am receiving undefined for the result of the token after calling refreshToken. How do you make the refresh call correctly?

Please see my code below. This is a controller method of Express and I am using mongoose and there is a User model in there.

exports.getItem = async (req, res) => {

  let { ebayItemId, user } = req.body // user is _id
  let result, token
  
  let { access_token } = await User.findById({_id: user}) // retrieve user and refresh tokens
  console.log(`access_token: `, access_token)

  eBay.auth.oAuth2.setCredentials(access_token);   // Get access token and pass it to this method

  try{ // make the call (which is expected to fail in order to activate the refresh token...)
    result = await eBay.browse.getItem(`v1|${ebayItemId}|0`)
  } catch (e) {
    console.log(`What's the problem #1...`, e)
  }
  
  try { // trying to get the refresh token
    token = await eBay.auth.oAuth2.refreshToken()
    token = await token.json()
    console.log(`New refreshed token? Check this: `, token)
  } catch (e) { // left out the error because it's enormous and contains the full request...
    console.log(`Token got a problem...`)
  }
  
  try {
    eBay.auth.oAuth2.setCredentials(token);
    result = await eBay.browse.getItem(`v1|${ebayItemId}|0`)
    result = await result.json()

  } catch (e) {
    console.log(`What's the problem #3...`, e)
  }

  console.log(`Final result: `, result)
  res.json(result)
}

The output I get is this...

What's the problem #1... TypeError: Cannot read property 'getItem' of undefined
    at exports.getItem (C:\Users\User\project_root\controllers\ebay.js:470:34)
    at process._tickCallback (internal/process/next_tick.js:68:7)
What's the problem #2
What's the problem #3... TypeError: Cannot read property 'getItem' of undefined
    at exports.getItem (C:\Users\User\project_root\controllers\ebay.js:490:34)
    at process._tickCallback (internal/process/next_tick.js:68:7)
Final result:  undefined

What is the correct way to obtain a new token from calling refreshToken?

I had saved both the access_token and refresh_token in the database from the initial authorization.

Days later, I wanted to test if this code worked as I knew it would be a hard expired access_token.

Finding Api attributes

how to pass attributes ? I was trying to pass something like this

    ```
    await eBay.finding.findItemsByProduct(
                {
                  productId: {
                    "_text": 53039031,
                    "_type": 'ReferenceID',
                  },
                },
                {
                  parseOptions: {
                    attributeNamePrefix: '_',
                    textNodeName: '_text',
                    ignoreAttributes: false,
                    parseNodeValue: true,
                    parseAttributeValue: false,
                  },
                })

but it fails with the error ProductID not found.

Help with authorization

Hi, I'm having problems with permissions and suspect I'm doing something stupid. I don't fully understand the eBay auth tokens.

This is what I'm using:

const eBay = new eBayApi({
    appId: "######################",
    certId: "######################",
    sandbox: true,

    scope: ["https://api.ebay.com/oauth/api_scope"],

    // optional parameters, should be omitted if not used
    siteId: eBayApi.SiteId.EBAY_UK, // required for traditional APIs, see https://developer.ebay.com/DevZone/merchandising/docs/Concepts/SiteIDToGlobalID.html
    devId: "######################", // required for traditional trading API
    //ruName: "######################", // required for authorization code grant
    //authToken: "", // can be set to use traditional API without code grant
  });

  eBay.sell.fulfillment
    .getOrders()
    .then((orders) => {
      console.log(JSON.stringify(orders, null, 2));
    })
    .catch((e) => {
      console.log(e);
    });

I'm currently getting the 'Insufficient permissions to fulfill the request.' error.

I can successfully get an Auth Token from using ebay-oauth-nodejs-client

const EbayAuthToken = require("ebay-oauth-nodejs-client");
  const ebayAuthToken = new EbayAuthToken({
    filePath: path.join(configDirectory, "eBayJson.json"),
    // input file path.
  });

  (async () => {
    const token = await ebayAuthToken.getApplicationToken("SANDBOX");
    console.log(token);
  })();

Can I use this token in your API call?

Thanks in advance for the help!

Site Id is staying on German even if I put the enum or manual number

Have my setup like this

   this.ebay = new eBayApi({
      appId: process.env.EBAY_APP_ID,
      certId: process.env.EBAY_CERT_ID,
      sandbox: false,
      scope: ['https://api.ebay.com/oauth/api_scope'],
      siteId: eBayApi.SiteId.EBAY_US,
      devId: process.env.EBAY_DEV_ID,
    });

Yet in the headers I keep seeing it set to German

headers: {
    'Content-Type': 'application/json',
    'Cache-Control': 'no-cache',
    'Accept-Encoding': 'application/gzip',
    'X-EBAY-C-MARKETPLACE-ID': 'EBAY_DE',
    Authorization: ...

I've tried with just 0 as well but the same issue. Any ideas?

findCompletedItems returns undefined

Hello, I observed findCompletedItems work once and then after I constantly get undefined.

Here is my code:

// set OAuth2 eBay credentials
eBay.auth.oAuth2.setCredentials(ebayAuthToken);

let post = {
  RequesterCredentials: {
    eBayAuthToken: ebayAuthToken
  },
  categoryId: categoryId,
  itemFilter: {
    name: `SoldItemsOnly`,
    value: true
  }
}

try {
let result = await eBay.finding.findCompletedItems(post)

console.log('result...')
console.log(result)
res.json(result)
} 

catch(e) {
  console.log(`Got error: `, e)
  res.json({error: e})
}

Is there any issue you can see with the code or is there an issue with this call?

Set grant type

Can you set grant type. I would like to set it to client_credentials

Obtaining eBay OAuth access code after user clicks

So, I am trying to obtain the eBay OAuth access_token (created when a user authorizes my app) back into my React app from the result of it being sent from ebay to an endpoint I created /api/ebayaccepted and have gotten stuck because I don't know how to get that back to my app once the access_token comes through.

I have created a page in React with a button meant to display an eBay OAuth link after user clicks.

If successful, eBay grants the access_token and sends it to my express endpoint /api/ebayaccepted.

However, I am doing all this testing from my local machine, namely localhost:3000 (frontend) and localhost:8000 (express backend). So, to bypass the https requirement by ebay (I am using http://localhost:8000 which is a no-no for the eBay redirect url), I am using ngrok to produce links that look like https://8e37hhnc176c.ngrok.io/ which go in the ebay RuName settings.

All is well and good until I have to obtain the access_token because by clicking the link created by clicking that initial button, it opens a new page that I cannot access the localstorage or cookie for. I am at a loss as to how to get this back to my redux React frontend app. I thought about having it write this token to a temp file on the server but I don't like that potential security risk.

How can I return the access_code returned from eBay to my app?

Attempts:

Tried res.cookie by returning a view page which ultimately showed me that wouldn't work because it's a new tab that opens and even tho you could put a cookie in, it just cannot be seen by my app :(
Tried res.send() with res.cookie but that STILL produces another unrelated tab

No documentation for refreshing tokens

From looking at the code, it appears to automatically refresh the token if a request is made with an expired token. However, I want to sometimes refresh the token myself (and store the token in a database), to avoid extra (wasted) API calls with an expired token.

I see there are refreshToken, refreshClientToken, and refreshAuthToken methods exposed in oAuth2, but no documentation on how to use them. I want to know how to retrieve the refreshed token that refreshAuthToken is presumably getting from eBay.

It's saying Return policy is not specified when clearly it's specified

I'm having a strange issue all of a sudden when trying to add a fixed price items to ebay. Here's the errors first...

  meta: [
    {
      ShortMessage: 'Return policy is not specified.',
      LongMessage: 'A return option is missing or not valid. Update your return options.',
      ErrorCode: 21916250,
      SeverityCode: 'Error',
      ErrorParameters: [Object],
      ErrorClassification: 'RequestError'
    },
    {
      ShortMessage: 'Return policy is not specified.',
      LongMessage: 'A return option is missing or not valid. Update your return options.',
      ErrorCode: 21916250,
      SeverityCode: 'Error',
      ErrorParameters: [Object],
      ErrorClassification: 'RequestError'
    },
    {
      ShortMessage: 'Return policy is not specified.',
      LongMessage: 'A return option is missing or not valid. Update your return options.',
      ErrorCode: 21916250,
      SeverityCode: 'Error',
      ErrorParameters: [Object],
      ErrorClassification: 'RequestError'
    },
    {
      ShortMessage: 'A shipping service is not specified.',
      LongMessage: 'At least one valid shipping service must be specified.',
      ErrorCode: 21915469,
      SeverityCode: 'Error',
      ErrorClassification: 'RequestError'
    }
  ]

Yet, here is what I am sending (I removed actual values but certainly the Returns/Shipping/Payment profiles and their corresponding id numbers are going into the request to ebay to list this)...

{
	"RequesterCredentials": {
		"eBayAuthToken": "<super long access_token>"
	},
	"Item": {
		"Title": "ACME Rosia Recliner in Gray",
		"Description": {
			"__cdata": "<p>For ultimate comfort, the Rosia linen recliner is covered with smooth fabric in various color options to match with any home decor. Additional back comfort is created by the vertical stitch line and tuft while the horizontal section makes room for your shoulders. Sweeping arched overstuffed armrests are added to the comfort level by elevating your arms at an angle while reclined.</p><br /><b>Features : </b><ul><li>Motion: Reclining Function</li><li>Tight Back and Seat Cushion</li><li>Seat: Pocket Coil</li><li>Pillow Top Arm</li><li>Arm With Cup Holder</li><li>External Latch Handle (No Power)</li></ul><br /><b>Specifications : </b><ul><li>Product Dimensions : 39\" H x 32\" W x 37\" D</li><li>Product Weight : 78 lbs</li></ul>"
		},
		"PrimaryCategory": {
			"CategoryID": "54235"
		},
		"StartPrice": 485.49,
		"CategoryMappingAllowed": true,
		"Country": "US",
		"Currency": "USD",
		"ConditionID": 1000,
		"ItemSpecifics": {
			"NameValueList": [{
				"name": "Material",
				"value": "Fabric"
			}, {
				"name": "Item Height",
				"value": "39\""
			}, {
				"name": "Collection",
				"value": "Rosia"
			}, {
				"name": "Item Width",
				"value": "32\""
			}, {
				"name": "Brand",
				"value": "ACME Furniture"
			}, {
				"name": "Item Length",
				"value": "37\""
			}, {
				"name": "Model",
				"value": "59549"
			}, {
				"name": "Category",
				"value": "Recliners"
			}, {
				"name": "Color",
				"value": "Gray"
			}, {
				"name": "California Prop. 65 Warning",
				"value": "Yes"
			}, {
				"name": "Type",
				"value": "Chair"
			}, {
				"name": "UPC",
				"value": "840412111617"
			}]
		},
		"DispatchTimeMax": 3,
		"ListingDuration": "GTC",
		"ListingType": "FixedPriceItem",
		"PictureDetails": {
			"PictureURL": ["<picture url>"]
		},
		"PostalCode": "90001",
		"Quantity": "1",
		"SellerProfiles": {
			"SellerShippingProfile": {
				"ShippingProfileID": "xxxxxxxxxxx",
				"ShippingProfileName": "myShippingPolicy"
			},
			"SellerReturnProfile": {
				"ReturnProfileID": "xxxxxxxxxxx",
				"ReturnProfileName": "myReturnsPolicy"
			},
			"SellerPaymentProfile": {
				"PaymentProfileID": "xxxxxxxxxxx",
				"PaymentProfileName": "myPaymentsPolicy"
			}
		}
	}
}

I am constantly getting the error that it's missing the Shipping, Returns, and Payment Profiles are not specified, preventing me from listing further. Please help!

Error [EbayApiError]: IAF token supplied is invalid. / 'invalid_grant' / 'the provided authorization refresh token is invalid or was issued to another client'

Hi, I have been successfully listing items to ebay on behalf of members of my site.

A problem has been happening for the past several days when it comes time to reprice/end their listings (on their behalf) and I attempt to relist items. I am receiving this error:

Got error:  Error [EbayApiError]: IAF token supplied is invalid.
    at EbayApiError.EBayError [as constructor] (/root/myserver/node_modules/@hendt/ebay-api/lib/errors/index.js:26:47)
    at new EbayApiError (/root/myserver/node_modules/@hendt/ebay-api/lib/errors/index.js:101:24)
    at XMLRequest.handleEBayJsonError (/root/myserver/node_modules/@hendt/ebay-api/lib/api/traditional/XMLRequest.js:270:19)
    at XMLRequest.<anonymous> (/root/myserver/node_modules/@hendt/ebay-api/lib/api/traditional/XMLRequest.js:247:30)
    at step (/root/myserver/node_modules/@hendt/ebay-api/lib/api/traditional/XMLRequest.js:63:23)
    at Object.next (/root/myserver/node_modules/@hendt/ebay-api/lib/api/traditional/XMLRequest.js:44:53)
    at fulfilled (/root/myserver/node_modules/@hendt/ebay-api/lib/api/traditional/XMLRequest.js:35:58)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:97:5) {
  meta: {
    ShortMessage: 'Invalid IAF token.',
    LongMessage: 'IAF token supplied is invalid.',
    ErrorCode: 21916984,
    SeverityCode: 'Error',
    ErrorClassification: 'RequestError'
  }
}

What could be the cause of this error?

I believe I am correctly generating User access tokens because they do succeed in listing the items initially.

However, the next day comes and my system tries to revise their listings (change price or end listing) and it throws the error that the IAF token supplied is invalid.

Here is my code that attempts to refresh the token below. Is it that I am generating the WRONG token every time??

exports.refreshEbayToken = async (user, eBay) => {  
    console.log(`Made it to refreshEbayToken with user...${user}`)
    let token
    let minutes
    // first check the age of the prior token

    try {
        let userData = await User.findById( {_id: user} ) // gets the user doc
        let { token_last_refresh } = userData // gets the last time the token was refreshed
        token = userData.token // assigns token from user doc to token variable
        let startDate = Date.parse(token_last_refresh) // gets last refreshed date/time
        let endDate = new Date() // creates new time as a reference point
        endDate = Date.parse(endDate) // makes it readable for next step
        let seconds = (endDate - startDate) / 1000; // get seconds
        minutes = seconds / 60; // get minutes
        console.log(`minutes since ebay token last refresh: `, minutes)
    } catch(e) { console.log(e) }
  
    if(minutes > 115) { // if 2 hours has not yet passed from minting a new one...
        try{
            token = await eBay.oAuth2.refreshClientToken() // gets the brand new application access token
            console.log(`Got the refresh token...`)
            try { // try to update the user doc with new token
                let userData = await User.findByIdAndUpdate(
                    {_id: user},
                    {$set: {
                        token: [token],
                        access_token: token.access_token,
                        token_last_refresh: Date.now()
                    }}
                    )
                token = userData.token // double confirm it's the right token by returning the overwritten doc token
                return token // send back token
            } catch(e) { console.log(e) }
        
          } catch(e) { console.log(e); return e }

    } else { // less than 2 hours since minting access token, return current token
        console.log(`Less than 2 hours since minting access token, sending current token instead...`)
        return token // send back token
    }
  }

Also, after noticing this page in your code, I switched my code from refreshClientToken to refreshToken but still I got that IAF error...

token = await eBay.oAuth2.refreshToken()

Please help me. I need to be able to reliably call ReviseFixedPriceItem as I am getting more members but everything is stopped due to this error.

Update: After refactoring my code again (thinking surely this time it will work) I got the following error (sorry it's the full error):

Error: Request failed with status code 400
    at createError (/root/project_directory/backend/node_modules/axios/lib/core/createError.js:16:15)
    at settle (/root/project_directory/backend/node_modules/axios/lib/core/settle.js:17:12)
    at IncomingMessage.handleStreamEnd (/root/project_directory/backend/node_modules/axios/lib/adapters/http.js:260:11)
    at IncomingMessage.emit (events.js:326:22)
    at IncomingMessage.EventEmitter.emit (domain.js:483:12)
    at endReadableNT (_stream_readable.js:1241:12)
    at processTicksAndRejections (internal/process/task_queues.js:84:21) {
  config: {
    url: 'https://api.ebay.com/identity/v1/oauth2/token',
    method: 'post',
    data: 'grant_type=refresh_token&scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.fulfillment.readonly%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.fulfillment%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.account%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.account.readonly%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.inventory.readonly%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.inventory',
    headers: {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/x-www-form-urlencoded',
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Headers': 'X-Requested-With, Origin, Content-Type, X-Auth-Token',
      'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE',
      'User-Agent': 'axios/0.21.1',
      'Content-Length': 500
    },
    auth: {
      username: '<removed>',
      password: '<removed>'
    },
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    adapter: [Function: httpAdapter],
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    validateStatus: [Function: validateStatus]
  },
  request: ClientRequest {
    _events: [Object: null prototype] {
      socket: [Function],
      abort: [Function],
      aborted: [Function],
      connect: [Function],
      error: [Function],
      timeout: [Function],
      prefinish: [Function: requestOnPrefinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: null,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    socket: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: false,
      _SNICallback: null,
      servername: 'api.ebay.com',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 10,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'api.ebay.com',
      _readableState: [ReadableState],
      readable: true,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: false,
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular],
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(asyncId)]: 16460,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object]
    },
    connection: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: false,
      _SNICallback: null,
      servername: 'api.ebay.com',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 10,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'api.ebay.com',
      _readableState: [ReadableState],
      readable: true,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: false,
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular],
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(asyncId)]: 16460,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object]
    },
    _header: 'POST /identity/v1/oauth2/token HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Content-Type: application/x-www-form-urlencoded\r\n' +
      'Access-Control-Allow-Origin: *\r\n' +
      'Access-Control-Allow-Headers: X-Requested-With, Origin, Content-Type, X-Auth-Token\r\n' +
      'Access-Control-Allow-Methods: GET, PUT, POST, DELETE\r\n' +
      'User-Agent: axios/0.21.1\r\n' +
      'Content-Length: 500\r\n' +
      'Host: api.ebay.com\r\n' +
      'Authorization: Basic <removed>==\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: noopPendingOutput],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object],
      requests: {},
      sockets: [Object],
      freeSockets: {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      maxTotalSockets: Infinity,
      totalSocketCount: 1,
      scheduling: 'fifo',
      maxCachedSessions: 100,
      _sessionCache: [Object],
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'POST',
    insecureHTTPParser: undefined,
    path: '/identity/v1/oauth2/token',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      readable: false,
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      socket: [TLSSocket],
      connection: [TLSSocket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      headers: [Object],
      rawHeaders: [Array],
      trailers: {},
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 400,
      statusMessage: 'Bad Request',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular],
      responseUrl: 'https://<removed>:<removed>@api.ebay.com/identity/v1/oauth2/token',
      redirects: [],
      [Symbol(kCapture)]: false
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'api.ebay.com',
    protocol: 'https:',
    _redirectable: Writable {
      _writableState: [WritableState],
      writable: true,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 500,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function],
      _currentRequest: [Circular],
      _currentUrl: 'https://<removed>:<removed>@api.ebay.com/identity/v1/oauth2/token',
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'content-type': [Array],
      'access-control-allow-origin': [Array],
      'access-control-allow-headers': [Array],
      'access-control-allow-methods': [Array],
      'user-agent': [Array],
      'content-length': [Array],
      host: [Array],
      authorization: [Array]
    }
  },
  response: {
    status: 400,
    statusText: 'Bad Request',
    headers: {
      rlogid: '<removed>',
      'x-ebay-c-version': '1.0.0',
      'x-ebay-client-tls-version': 'TLSv1.3',
      'x-frame-options': 'SAMEORIGIN',
      'x-content-type-options': 'nosniff',
      'x-xss-protection': '1; mode=block',
      'set-cookie': [Array],
      'content-type': 'application/json',
      'content-length': '131',
      date: 'Mon, 07 Jun 2021 23:45:59 GMT',
      server: 'ebay-proxy-server',
      'x-envoy-upstream-service-time': '38',
      'x-ebay-pop-id': 'UFES2-RNOAZ03-api',
      connection: 'close'
    },
    config: {
      url: 'https://api.ebay.com/identity/v1/oauth2/token',
      method: 'post',
      data: 'grant_type=refresh_token&scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.fulfillment.readonly%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.fulfillment%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.account%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.account.readonly%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.inventory.readonly%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.inventory',
      headers: [Object],
      auth: [Object],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      adapter: [Function: httpAdapter],
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      validateStatus: [Function: validateStatus]
    },
    request: ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: null,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      socket: [TLSSocket],
      connection: [TLSSocket],
      _header: 'POST /identity/v1/oauth2/token HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Content-Type: application/x-www-form-urlencoded\r\n' +
        'Access-Control-Allow-Origin: *\r\n' +
        'Access-Control-Allow-Headers: X-Requested-With, Origin, Content-Type, X-Auth-Token\r\n' +
        'Access-Control-Allow-Methods: GET, PUT, POST, DELETE\r\n' +
        'User-Agent: axios/0.21.1\r\n' +
        'Content-Length: 500\r\n' +
        'Host: api.ebay.com\r\n' +
        'Authorization: Basic <removed>==\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: noopPendingOutput],
      agent: [Agent],
      socketPath: undefined,
      method: 'POST',
      insecureHTTPParser: undefined,
      path: '/identity/v1/oauth2/token',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'api.ebay.com',
      protocol: 'https:',
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype]
    },
    data: {
      error: 'invalid_grant',
      error_description: 'the provided authorization refresh token is invalid or was issued to another client'
    }
  },
  isAxiosError: true,
  toJSON: [Function: toJSON]
}


Token giving access to ebay store question

Hey...I'm sorry to come back with another question.

With my GetNotificationPreferences, and SetNotificationPreferences and getOrders working in sandbox. I've added some production keys.
I've then got the owner of the ebay store account to log in and authorize a token and stored the token locally. And I can use that token to get notification preferences and orders, getting success API responses.

However, it's not bringing back ANY orders, and I'm not getting any notifications even though they have been set by the API. I can even use the API Explorer in eBay to check with the token: -

image

image

What am I missing? Why can't I get orders from the ebay store.
I'm using the sandbox = false; and the production cert, app ids etc...

Hi how to address that cannot use import

I want to use this module in aws Lambda/cloud9, but I can't import it in my js file, only can use 'require'. I found many ways to transforms the two forms, but they all can't be used in Lambda this cloud server platform.

Listing success responds with error

Got a weird one which I suspect is more on Ebay's side, but as of today, when I use trading.ReviseFixedPriceItem on a managed payment account, the listing is correctly listed, but instead of returning the listing, it returns the standard ebay error response, with a warning "This selling account is enabled for payments managed by eBay. PayPal is not currently accepted as a payment method and has been removed from the listing."

Example buying an item from ebay?

Hello, thanks a lot for sharing this library, I really appreciate your work!

I'm trying to figure out a way to:

  1. Find and item I'm looking for ( for instance Madonna - Like a Virgin )
  2. Select the itemId from the search query
  3. Buy the item using my ebay and paypal account

This way I could "Automatically buy" an item that meets my requirements.

I tried to understand how this works from the eBay Documentation but I didn't manage to find a way yet, hopefully it's going to be much easier using your library.

Again, thank you very much.

Unable to perform getOrders / Error - Insufficient permissions to fulfill the request

Hi I am having no success with the getOrders call.

Here's the auth scopes I'm using when setting the ORIGINAL User access token...:

      eBay.auth.oAuth2.setScope([
        'https://api.ebay.com/oauth/api_scope',
        'https://api.ebay.com/oauth/api_scope/sell.marketing.readonly',
        'https://api.ebay.com/oauth/api_scope/sell.marketing',
        'https://api.ebay.com/oauth/api_scope/sell.inventory.readonly',
        'https://api.ebay.com/oauth/api_scope/sell.inventory',
        'https://api.ebay.com/oauth/api_scope/sell.account',
        'https://api.ebay.com/oauth/api_scope/sell.account.readonly',
        'https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly',
        'https://api.ebay.com/oauth/api_scope/sell.fulfillment',
        'https://api.ebay.com/oauth/api_scope/sell.analytics.readonly',
        'https://api.ebay.com/oauth/api_scope/sell.finances',
        'https://api.ebay.com/oauth/api_scope/sell.payment.dispute',
        'https://api.ebay.com/oauth/api_scope/commerce.identity.readonly',
    ]);

Here's my code (ExpressJS backend controller method...):

exports.getOrders = async (req, res) => { 
  let  _id = req.params.userId; // user's _id
  let token = await refreshEbayToken(_id, eBay)
  console.log(`token...`, token) // not an array!  It's an object!

  // set OAuth2 eBay credentials
  eBay.auth.oAuth2.setCredentials(token.access_token);

  try {
    let result = await eBay.sell.fulfillment.getOrders({
      filter: 'orderfulfillmentstatus:{NOT_STARTED|IN_PROGRESS}',
        limit: 5
    })
    console.log(`Got a result...`, result)
    res.json(result)
  } catch (e) {
    console.log(`Got an error in getOrders...`, e)
    res.status(400).json( { error: e } )
  }
  
}

Here's the error I get:

{
        "meta": {
            "errors": [
                {
                    "errorId": 1100,
                    "domain": "ACCESS",
                    "category": "REQUEST",
                    "message": "Access denied",
                    "longMessage": "Insufficient permissions to fulfill the request."
                }
            ]
        },
        "name": "EBayAccessDenied"
    }

Even freshly minted User access tokens through those scopes get this error.

According to the ebay docs on getOrders, these are the required auth scopes for this call:

https://api.ebay.com/oauth/api_scope/sell.fulfillment
https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly

Upon further investigation, I found I am certainly using those scopes in the response (below is a snippet of the scopes grabbed from the larger ebay error)...

...%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.fulfillment.readonly%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.fulfillment%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.analytics.readonly%20https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.finances%20...

As shown above, I am clearly using the sell.fulfillment and sell.fulfillment.readonly scopes so I do not understand what is the issue.

How are you making your getOrders calls successfully?

UPDATE: I successfully made a getOrders call but did it using fetch (tho I rather use hendt/ebay-api) but here's the code which actually works for me now (until we could solve this)...

exports.getOrders2 = async (req, res) => { 
  let  _id = req.params.userId; // user's _id
  let token = await refreshEbayToken(_id, eBay)
  if(Array.isArray(token) === true) {
    console.log(`Converting token from array to object...`)
    token = token[0]
  }
  console.log(`token...`, token) // not an array!  It's an object!

  try {
    let result = await fetch(`https://api.ebay.com/sell/fulfillment/v1/order`, {
      method: "GET",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        Authorization: `Bearer ${token.access_token}`
      },
    })
    result = await result.json()
    console.log(`Got a result...`, result)
    // res.json(result)
  } catch (e) {
    console.log(`Got an error in getOrders...`, e)
    res.status(400).json( { error: e } )
  }
  
}

Getting this output from that...

{
    "href": "https://api.ebay.com/sell/fulfillment/v1/order?limit=50&offset=0",
    "total": 0,
    "limit": 50,
    "offset": 0,
    "orders": []
}

How to you call getFulfillmentPolicy?

I need to use the getFulfillmentPolicy call and tried to use hendt / ebay-api to do it.

Here is the code I am trying to use but it is failing:

exports.getFulfillmentPolicy = async ( req, res ) => {
  console.log( `Made it to getFulfillmentPolicy!  Here's req.body...`, req.body )
  let user = req.body.user
  let fulfillmentPolicyId = req.body.fulfillmentPolicyId
  try {
    let _user = await User.findById({_id: user})
    console.log(`_user.token...`, _user.token)
    eBay.auth.oAuth2.setCredentials(_user.token[0])
    let result = await eBay.sell.getFulfillmentPolicy({ fulfillmentPolicyId })
    console.log( `result...`, result )
    res.json( result )
  } catch ( e ) { console.log( `Got an error in getFulfillmentPolicy...`, e ); res.json( { error: e } ) }
}

Error Response...

TypeError: eBay.sell.getFulfillmentPolicy is not a function

Can you please share how to properly make this call?

Add enums

Many types are enums, defined by eBay. These enums should be added so that types can be restricted to these enums, instead of strings.

For example, the type CategoryType, which is currently:

export type CategoryType = {
    default?: boolean
    name: string
}

Would become:

export type CategoryType = {
    default?: boolean
    name: CategoryTypeEnum
}

The enum CategoryTypeEnum could be defined as:

export enum CategoryTypeEnum {
    MOTORS_VEHICLES = 'MOTORS_VEHICLES',
    ALL_EXCLUDING_MOTORS_VEHICLES = 'ALL_EXCLUDING_MOTORS_VEHICLES'

Or, to use TypeScript case conventions:

export enum CategoryTypeEnum {
    MotorsVehicles = 'MOTORS_VEHICLES',
    AllExcludingMotorsVehicles = 'ALL_EXCLUDING_MOTORS_VEHICLES'
}

This will improve type safety in the library.

Is there a way to control DetailLevel in the getItem call?

I need a reliable way to get the quantity sold for any valid ebay item. I used your library and specifically the getItem call. It worked except I noticed it was missing Item.SellingStatus.QuantitySold in the responses. How can I use hendt / ebay-api to get this value?

I was thinking maybe the call is not passing in DetailLevel and that's the reason it's not in the response. Could this be the case and if so, is there a way to pass in the DetailLevel parameter as "ReturnAll"

Access denied: Insufficient permissions to fulfill the request

Hello,

I've written this simple script:

const _fulfillment = eBay.factory.createSellApi().fulfillment;
_fulfillment.getOrders().then(item => {
  console.log(JSON.stringify(item, null, 2));
}).catch(e => {
  console.error(JSON.stringify(e));
});

And am getting this error:

EBayAccessDenied: Access denied: Insufficient permissions to fulfill the request.
    at EBayAccessDenied.EBayError [as constructor] 

Can you help me diagnose what's wrong with the permissions? Is that on the @hendt/ebay-api library side or my eBay sandbox configuration?

Complex aspect filters with spaces don't work

example:

will return correctly filtered items

 this.api.buy.browse.search({
        q: searchTerm,
        category_ids: "15709",
        sort: "price",
        aspect_filter: "categoryId:15709,Color:{Red}",
        limit: limit,
        offset: offset || 0,
      });

will return items but will totally ignore aspect_filter

 this.api.buy.browse.search({
        q: searchTerm,
        category_ids: "15709",
        sort: "price",
        aspect_filter: "categoryId:15709,US Shoe Size(Men's):{7}",
        limit: limit,
        offset: offset || 0,
      });

also tried encoding the aspect filter string before calling search, but the same issue

Not able to create proxy server

Please Can anyone help me to create the proxy server for the request? I installed @hendt/ebay-api server and put the worker file in the proxy folder.
image

ebay post-order api all operations return 401, any ideas?

I'm getting 401 for all postOrder.case.search(), postOrder.inquier.search() and postOrder.return.search()

Any ideas? Thanks

const api = new EbayApi({
  appId: channel.credential.appId,
  devId: channel.credential.devId,
  certId: channel.credential.certId,
  sandbox: false,
  siteId: EbayApi.SiteId.EBAY_US,
});

const returns = await channel.api.postOrder.return.search({});
console.dir(returns, { depth: Infinity });

Getting error details

When using the bulk create offer endpoint, e.g.:

try {
	return await this.ebay.sell.inventory.bulkCreateOffer({ requests });
} catch (e) {
	console.log(e);
}

I get this from the console:

EBayError: Request failed with status code 400
    at new EBayError ([REPO]\node_modules\@hendt\ebay-api\src\errors\index.ts:17:5)
    at Object.exports.handleEBayError ([REPO]\node_modules\@hendt\ebay-api\src\errors\index.ts:179:2)
    at Inventory.<anonymous> ([REPO]\node_modules\@hendt\ebay-api\src\api\restful\index.ts:204:7)
    at step ([REPO]\node_modules\@hendt\ebay-api\lib\api\restful\index.js:57:23)
    at Object.throw ([REPO]\node_modules\@hendt\ebay-api\lib\api\restful\index.js:38:53)
    at rejected ([REPO]\node_modules\@hendt\ebay-api\lib\api\restful\index.js:30:65)
    at processTicksAndRejections (internal/process/task_queues.js:95:5) {
  meta: {
    res: { status: 400, statusText: 'Bad Request', headers: [Object] },
    req: {
      url: 'https://api.ebay.com/sell/inventory/v1/bulk_create_offer',
      method: 'post',
      headers: [Object],
      params: undefined
    },
    [Symbol(raw-error)]: Error: Request failed with status code 400
        at createError ([REPO]\node_modules\axios\lib\core\createError.js:16:15)
        at settle ([REPO]\node_modules\axios\lib\core\settle.js:17:12)
        at Unzip.handleStreamEnd ([REPO]\node_modules\axios\lib\adapters\http.js:260:11)
        at Unzip.emit (events.js:376:20)
        at endReadableNT (internal/streams/readable.js:1336:12)
        at processTicksAndRejections (internal/process/task_queues.js:82:21) {
      config: [Object],
      request: [ClientRequest],
      response: [Object],
      isAxiosError: true,
      toJSON: [Function: toJSON]
    }
  }
}

This is the response I get when sending the request to eBay via their web tool, which includes the duplicated offer ID that I need. I can't find any way to get this from the e that is thrown by the bulkCreateOffer request.

{
  "responses": [
    {
      "statusCode": 400,
      "sku": "REDACTED",
      "marketplaceId": "EBAY_AU",
      "format": "FIXED_PRICE",
      "warnings": [],
      "errors": [
        {
          "errorId": 25002,
          "domain": "API_INVENTORY",
          "subdomain": "Selling",
          "category": "REQUEST",
          "message": "A user error has occurred. Offer entity already exists.",
          "parameters": [
            {
              "name": "offerId",
              "value": "78...[REDACTED]...18"
            }
          ]
        }
      ]
    }
  ]
}

Getting strange XML Errors When Listing

Hi, I'm getting XML Parse errors but cannot find where it's coming from.

Error

{
  meta: {
    ShortMessage: 'XML Parse error.',
    LongMessage: 'XML Error Text: &quot;; nested exception is: \n' +
      '\torg.xml.sax.SAXParseException: The entity name must immediately follow the &apos;&amp;&apos; in the 
entity reference.&quot;.',
    ErrorCode: 5,
    SeverityCode: 'Error',
    ErrorParameters: {
      Value: '; nested exception is: \n' +
        '\torg.xml.sax.SAXParseException: The entity name must immediately follow the &apos;&amp;&apos; in the entity reference.'
    },
    ErrorClassification: 'RequestError'
  }
}

My description is as follows:

    Description: {
      __cdata: '<div>Now you can enjoy the authentic taste of wood-fired pizza made from scratch in your own 
home. This clay oven is sure to be a hit with friends and family and will add hours of enjoyment to parties. 
Showcase your skills cooking the perfect pie as you teach others the art of baking in a wood-fired oven. Ideal for large family style pies, individual pizzas and breads. You will need to purchase white sand (sold separately) for an insulating layer underneath the pizza stones inside the oven. Includes: clay oven, pizza stone, ember rake and stand Wide mouth for easy placement and retrieval of pizzas We recommend using hardwoods like oak, beech or birch that have been kiln dried, fruit woods can be used for flavor, but avoid sappy soft woods Cover, pizza peels and sand for insulation sold separately For outdoor use only with wood, not for use with charcoal, do not use chemical fire starters Be sure to allow for oven to cool completely before covering.</div>'
    }

I can't see where the issue is.

Can you help?

API translates my listings into German

new eBayApi({
	appId: config.eBay.clientID,
	certId: config.eBay.clientSecret,
	sandbox: false,
	siteId: eBayApi.SiteId.EBAY_GB,
	scope: [
		"https://api.ebay.com/oauth/api_scope",
	],
	acceptLanguage: "en-GB",
	contentLanguage: ContentLanguage.en_GB,
});

this.ebay.oAuth2.getClientAccessToken()`

This is how I initialize the API wrapper. Later I call

let item = await this.ebay.buy.browse.getItemByLegacyId({
	legacy_item_id: itemID,
});

This query works, but the title of the listing is translated into German from English.
For example. the title Samsung SMT-C7100/C7101 500GB Boxed with Remote Control NEW becomes Samsung smt-c7100/c7101 500gb boxed mit Fernbedienung NEU but the description remains in English. Also, some details such as condition are also translated into German, such as condition, neu. The price is also converted into Euros.

Help with this would be appreciated.

Having Tough Time Getting AddFixedPriceItem to list an item

Hi, I am trying to use your library with ExpressJS.

Not sure if I'm even doing this right but I have set up 4 endpoints to handle the 4 parts mentioned in your README.md:

// Step 1: Generate OAuth URL
router.post("/ebay/getoauthurl", generateEbayOauthUrl)
// Step 2: Get eBay Code
router.post("/ebayaccepted", getEbayCode)
// Step 3: get eBay Token and save to localhost
router.post("/ebay/gettoken", getToken)
// Step 4: Add Fixed Price Item
router.post("/ebay/addfixedpriceitem", addFixedPriceItem)

So, in Step 1, the controller method looks like this:

exports.generateEbayOauthUrl = ( req, res ) => {
    eBay.auth.oAuth2.setScope([
      'https://api.ebay.com/oauth/api_scope',
      'https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly',
      'https://api.ebay.com/oauth/api_scope/sell.fulfillment'
  ]);

  const url = eBay.auth.oAuth2.generateAuthUrl();
  // 2. Open Url and Grant Access
  console.log('Open URL', url);
  res.json(url)
  
}

This endpoint successfully works and I get the response containing the url.
I am testing this in Postman, so when I see the url, I click it and then see in the browser the code in the url params.

After, I take that code and send it to Step 2, like so:

exports.getEbayCode = ( req, res ) => {
  let code = req.params.code
  const expires_in = req.params.expires_in
  res.json({code, expires_in})

}

But when I try to get the token, it fails. Here is my code to handle getting the token:

exports.getToken = async (req, res) => {
  let code = req.body.code  // oauth granted code
  
  const token = await eBay.auth.oAuth2.getToken(code);

  let result = eBay.auth.oAuth2.setCredentials(token);
  res.json(result)

}

Here is what the error shows:

(node:20020) UnhandledPromiseRejectionWarning: Error: Request failed with status code 400
    at createError (C:\Users\Eric\Desktop\wiki\e\ebay\ebay-selling-platform\backend\node_modules\axios\lib\core\createError.js:16:15)
    at settle (C:\Users\Eric\Desktop\wiki\e\ebay\ebay-selling-platform\backend\node_modules\axios\lib\core\settle.js:17:12)
    at IncomingMessage.handleStreamEnd (C:\Users\Eric\Desktop\wiki\e\ebay\ebay-selling-platform\backend\node_modules\axios\lib\adapters\http.js:260:11)
    at IncomingMessage.emit (events.js:327:22)
    at IncomingMessage.EventEmitter.emit (domain.js:486:12)
    at endReadableNT (_stream_readable.js:1327:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)
(node:20020) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with 
.catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3)
(node:20020) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

As a result, I never make it to list the AddFixedPriceItem call to try to list.

I am pretty sure I got the above steps wrong but I did not find any examples of what a successful call from beginning to end is.

Please help and give guidance so I can finally use this library to list items to ebay! Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.