Updated Oct 2026
eBay Feedback API in Python: OAuth, feedback received, replies
eBay doesn’t have product reviews for sellers; it has feedback: positive, neutral or negative, with a comment, per order. The Commerce Feedback API reads it and lets the seller respond, once, in 80 characters. This guide does the OAuth dance, the listing and the response in requests, as Prisma’s eBay connector does, then the same through Prisma. The marketplace picture (eBay, Etsy, Mercado Libre, Amazon) is on marketplace seller reviews API.
pip install requestsFrom the eBay Developer Program: an app’s client id and client secret, and a RuName (redirect URL name) for the user consent flow. The token needs the scopes https://api.ebay.com/oauth/api_scope/commerce.feedback and https://api.ebay.com/oauth/api_scope/commerce.identity.readonly.
1. User consent and tokens
import os, base64, urllib.parse, requests
API = "https://api.ebay.com"
SCOPES = "https://api.ebay.com/oauth/api_scope/commerce.feedback https://api.ebay.com/oauth/api_scope/commerce.identity.readonly"
BASIC = "Basic " + base64.b64encode(f"{os.environ['EBAY_CLIENT_ID']}:{os.environ['EBAY_CLIENT_SECRET']}".encode()).decode()
# 1) send the seller here once
consent_url = "https://auth.ebay.com/oauth2/authorize?" + urllib.parse.urlencode({
"client_id": os.environ["EBAY_CLIENT_ID"], "redirect_uri": os.environ["EBAY_RUNAME"], "response_type": "code", "scope": SCOPES})
# 2) exchange the code from your redirect for tokens
def exchange(code):
r = requests.post(f"{API}/identity/v1/oauth2/token", headers={"Authorization": BASIC, "Content-Type": "application/x-www-form-urlencoded"},
data={"grant_type": "authorization_code", "code": code, "redirect_uri": os.environ["EBAY_RUNAME"]}, timeout=30)
r.raise_for_status(); return r.json() # access_token (2 h), refresh_token (18 months)
# 3) later: refresh
def refresh(refresh_token):
r = requests.post(f"{API}/identity/v1/oauth2/token", headers={"Authorization": BASIC, "Content-Type": "application/x-www-form-urlencoded"},
data={"grant_type": "refresh_token", "refresh_token": refresh_token, "scope": SCOPES}, timeout=30)
r.raise_for_status(); return r.json()["access_token"]
TOKEN = refresh(os.environ["EBAY_REFRESH_TOKEN"])
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}Access tokens last two hours, refresh tokens eighteen months. Store the refresh token encrypted.
2. Who am I, and the feedback received
me = requests.get("https://apiz.ebay.com/commerce/identity/v1/user/", headers=H, timeout=30).json()
USERNAME = me["username"]
STARS = {"POSITIVE": 5, "NEUTRAL": 3, "NEGATIVE": 1}
def feedback_received(username, limit=100):
offset = 0
while True:
r = requests.get(f"{API}/commerce/feedback/v1/feedback", headers=H, timeout=30,
params={"user_id": username, "feedback_type": "FEEDBACK_RECEIVED", "sort": "TIME", "limit": limit, "offset": offset})
r.raise_for_status()
entries = r.json().get("feedbackEntries", [])
if not entries:
break
yield from entries
offset += limit
for fb in feedback_received(USERNAME):
item = fb.get("orderLineItemSummary") or {}
print(fb["feedbackId"], fb["commentType"], STARS[fb["commentType"]], fb["feedbackEnteredDate"], item.get("listingTitle"),
(fb.get("feedbackComment") or {}).get("commentText", "")[:60], "| replied" if (fb.get("replyComment") or {}).get("commentText") else "")Each entry has feedbackId, commentType (POSITIVE, NEUTRAL, NEGATIVE), feedbackEnteredDate, feedbackComment.commentText, the listing in orderLineItemSummary (title and listingId, so you can link https://www.ebay.com/itm/<listingId>), your replyComment if you answered, the buyer’s followupComment if they came back, and providerUserDetail.userId, the buyer, which the reply needs. The buyer’s name isn’t exposed.
3. Respond (once, 80 characters)
fb_id = fb["feedbackId"]
one = requests.get(f"{API}/commerce/feedback/v1/feedback", headers=H, timeout=30,
params={"feedback_id": fb_id, "feedback_type": "FEEDBACK_RECEIVED", "user_id": USERNAME}).json()["feedbackEntries"][0]
requests.post(f"{API}/commerce/feedback/v1/respond_to_feedback", headers=H, timeout=30,
json={"feedbackId": fb_id, "recipientUserId": one["providerUserDetail"]["userId"],
"responseText": "Sorry about the delay. Refund sent, thanks for your patience.", "responseType": "REPLY"}).raise_for_status()The response is limited to 80 characters, is public, and can’t be edited or deleted. A FOLLOWUP responseType exists for the buyer’s side; sellers use REPLY. Because there is no delete, don’t retry a timed-out POST blindly; read the feedback back first and check replyComment.
4. The same job through Prisma
Prisma connects an eBay seller with eBay’s sign-in (OAuth; no developer account needed on your side), keeps the tokens, syncs feedback received, maps the three values to 5, 3 and 1 stars next to the original, and publishes replies through respond_to_feedback with the 80-character limit enforced before sending (reply_too_long otherwise). One key covers eBay plus Etsy, Judge.me, Google and 50+ other platforms.
H = {"Authorization": f"Bearer {os.environ['PRISMA_API_KEY']}"}
r = requests.get("https://api.prismareviews.com/v1/reviews", headers=H, params={"platform": "ebay", "has_reply": "false", "limit": 100}, timeout=30)
for rev in r.json()["data"]:
print(rev["rating"], rev["title"], rev["text"], rev["url"])
requests.post(f"https://api.prismareviews.com/v1/reviews/{rev['id']}/reply", headers=H,
json={"text": "Sorry about the delay. Refund sent, thanks for your patience."}, timeout=30).raise_for_status()Replies on eBay through Prisma are live today. If eBay never answers the request, Prisma marks the reply unknown instead of retrying, because a duplicate couldn’t be removed (why). Connection: POST /v1/connections with platform: "ebay" and a redirect_url; the seller signs in with eBay (Connections).
FAQ
Which eBay API returns seller feedback?
The Commerce Feedback API (commerce/feedback/v1) on api.ebay.com, with a user access token carrying the commerce.feedback scope. The older Trading API’s GetFeedback also works but the REST one is the current route.
How long can an eBay feedback reply be?
80 characters. The response is posted with respond_to_feedback, needs the feedback id and the id of the user who left it, and can’t be edited or deleted afterwards.
How do positive, neutral and negative map to stars?
eBay feedback has three values, not stars. Prisma maps POSITIVE to 5, NEUTRAL to 3 and NEGATIVE to 1 so eBay sits next to 5-star platforms in one feed; keep the original commentType for reporting.
eBay feedback next to your Google and Etsy reviews.
2 locations free. Test keys return sample feedback, so the code runs today.