18 KiB
eBay REST Client Usage Guide
This guide is the practical companion to the project README. Use it when you want to answer one of these questions quickly:
- Which scopes do I need for a workflow?
- Should I use
EbayClientdirectly orEbayOAuthClienttoo? - Which wrapper method matches the eBay operation I want?
- What are the implementation caveats around webhooks, disputes, uploads, or refunds?
1. Choose the Right Auth Model
There are two supported patterns.
Pattern A: Wrapper-first usage
Use this when you want to call the REST wrappers and let the transport fetch tokens automatically.
from ebay_client import EbayClient
from ebay_client.core.auth.models import EbayOAuthConfig
oauth_config = EbayOAuthConfig(
client_id="your-client-id",
client_secret="your-client-secret",
default_scopes=[
"https://api.ebay.com/oauth/api_scope/sell.inventory",
],
)
client = EbayClient(oauth_config)
items = client.inventory.get_inventory_items(limit=25)
This is the simplest mode. The transport asks the OAuth layer for a token whenever a wrapper call needs one.
Pattern B: Shared OAuth and wrapper usage
Use this when you need authorization-code flow, refresh tokens, or a shared persistent token store.
from ebay_client import EbayClient
from ebay_client.core.auth.models import EbayOAuthConfig
from ebay_client.core.auth.oauth import EbayOAuthClient
from ebay_client.core.auth.store import InMemoryTokenStore
store = InMemoryTokenStore()
oauth_config = EbayOAuthConfig(
client_id="your-client-id",
client_secret="your-client-secret",
redirect_uri="https://your-app.example/callback",
default_scopes=[
"https://api.ebay.com/oauth/api_scope",
"https://api.ebay.com/oauth/api_scope/commerce.notification.subscription",
],
)
oauth = EbayOAuthClient(oauth_config, token_store=store)
authorization_url = oauth.build_authorization_url(state="csrf-token")
client = EbayClient(oauth_config, token_store=store)
Key point: if you want the wrapper layer and your own OAuth flow to see the same token state, use the same TokenStore instance for both.
2. Scope Planning
The wrappers already encode the required scopes for each endpoint, but it still helps to know the scope families when you prepare credentials or interactive consent.
Core scope families
- Notification management:
https://api.ebay.com/oauth/api_scope - Notification subscriptions:
https://api.ebay.com/oauth/api_scope/commerce.notification.subscription - Notification subscription readonly:
https://api.ebay.com/oauth/api_scope/commerce.notification.subscription.readonly - Inventory write:
https://api.ebay.com/oauth/api_scope/sell.inventory - Inventory readonly:
https://api.ebay.com/oauth/api_scope/sell.inventory.readonly - Fulfillment write:
https://api.ebay.com/oauth/api_scope/sell.fulfillment - Fulfillment readonly:
https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly - Account write:
https://api.ebay.com/oauth/api_scope/sell.account - Account readonly:
https://api.ebay.com/oauth/api_scope/sell.account.readonly - Refunds:
https://api.ebay.com/oauth/api_scope/sell.finances - Payment disputes:
https://api.ebay.com/oauth/api_scope/sell.payment.dispute - Media workflows:
https://api.ebay.com/oauth/api_scope/sell.inventory - Feed endpoints accept one of several allowed scope families depending on the business domain behind the feed
How the client behaves
- Read wrappers often accept either the readonly scope or the broader write scope.
- If a broader valid token is already cached, it is reused.
- Write wrappers request the stronger scope directly.
- If the current token does not satisfy the endpoint, the OAuth layer fetches a new token for the required scope set.
default_scopesare mainly the fallback used when you explicitly call OAuth methods without passing scopes yourself.
3. Top-Level Client Map
EbayClient exposes these subclients:
client.notificationclient.inventoryclient.fulfillmentclient.accountclient.feedclient.media
Use the generated model packages for request and response types:
ebay_client.generated.notification.modelsebay_client.generated.inventory.modelsebay_client.generated.fulfillment.modelsebay_client.generated.account.modelsebay_client.generated.feed.modelsebay_client.generated.media.models
4. Common Workflows
This section maps typical seller workflows to wrapper methods.
Quick source jumps:
- facade: ebay_client/client.py
- notification wrapper: ebay_client/notification/client.py
- inventory wrapper: ebay_client/inventory/client.py
- fulfillment wrapper: ebay_client/fulfillment/client.py
- account wrapper: ebay_client/account/client.py
- feed wrapper: ebay_client/feed/client.py
- media wrapper: ebay_client/media/client.py
- FastAPI webhook example: examples/fastapi_notification_webhook.py
- media workflows example: examples/media_workflows.py
- inventory publish example: examples/inventory_publish_flow.py
- feed task example: examples/feed_task_flow.py
Notification: manage webhook subscriptions
Typical flow:
- inspect available topics with
get_topics() - create or update a destination with
create_destination()orupdate_destination() - create the subscription with
create_subscription() - optionally attach filters with
create_subscription_filter() - validate delivery with
test_subscription()
Use when you need:
- destination CRUD
- subscription CRUD
- enable or disable subscriptions
- lookup of eBay notification public keys
Notification: receive and verify inbound events
Inbound notifications do not use bearer-token auth. They use the X-EBAY-SIGNATURE header and eBay's public-key verification flow.
Recommended server flow:
- answer the GET challenge with
WebhookRequestHandler.handle_challenge() - resolve the public key through
WebhookPublicKeyResolver - verify the POST body with
WebhookSignatureValidator - dispatch the parsed
WebhookEventEnvelope
Reference implementation: examples/fastapi_notification_webhook.py.
Inventory: read listings and inventory records
Use these methods when you want to inspect the seller's inventory state:
get_inventory_item()get_inventory_items()bulk_get_inventory_item()get_offer()get_offers()get_listing_fees()get_inventory_location()get_inventory_locations()
This is the best starting point if your main use case is reading the data of already listed items.
Inventory: create or update listings
The common progression is:
- create or replace the inventory item with
create_or_replace_inventory_item() - configure location data if needed with
create_inventory_location()orupdate_inventory_location() - create the offer with
create_offer() - publish the offer with
publish_offer()
Bulk variants are available for larger batch flows:
bulk_create_or_replace_inventory_item()bulk_create_offer()bulk_publish_offer()bulk_update_price_quantity()
Caveat: several write methods require content_language=... and the wrapper enforces that explicitly.
Inventory: multi-variation and mapping support
Use these methods for additional listing structures:
- inventory item groups:
get_inventory_item_group(),create_or_replace_inventory_item_group(),delete_inventory_item_group() - product compatibility:
get_product_compatibility(),create_or_replace_product_compatibility(),delete_product_compatibility() - location mapping:
get_sku_location_mapping(),create_or_replace_sku_location_mapping(),delete_sku_location_mapping() - listing migration:
bulk_migrate_listing()
Fulfillment: orders and shipping fulfillments
Typical order handling flow:
- read orders with
get_orders()orget_order() - create shipment details with
create_shipping_fulfillment() - inspect resulting records with
get_shipping_fulfillments()orget_shipping_fulfillment()
Helper returned by create:
CreatedShippingFulfillment, which includes theLocationheader value and the extracted fulfillment ID
Fulfillment: refunds
Use issue_refund() with IssueRefundRequest when the seller workflow is eligible for the standard OAuth-backed refund path.
Caveats:
- this method uses the
sell.financesscope instead of the normal fulfillment scope - eBay documents additional Digital Signatures requirements for some refund scenarios, especially for some EU and UK sellers
- that Digital Signatures flow is not implemented in this client yet
Fulfillment: payment disputes
Dispute support is separated from regular fulfillment because eBay serves it from a different host and scope.
Methods:
- reads:
get_payment_dispute(),get_payment_dispute_summaries(),get_payment_dispute_activities() - decisions:
contest_payment_dispute(),accept_payment_dispute() - evidence files:
upload_evidence_file(),fetch_evidence_content() - evidence metadata:
add_evidence(),update_evidence()
Caveats:
- dispute methods use the
sell.payment.disputescope - dispute methods target
https://apiz.ebay.com/sell/fulfillment/v1/... - the shared transport already supports absolute URLs, so this is handled inside the wrapper
Account: business policies and seller capabilities
Use the Account wrapper for policy management and seller-level configuration reads.
Business policy coverage:
- fulfillment policies: list, get, create, update, delete, get-by-name
- payment policies: list, get, create, update, delete, get-by-name
- return policies: list, get, create, update, delete, get-by-name
Seller capability reads:
get_privileges()get_opted_in_programs()
This wrapper is a good fit when you need to prepare the policy IDs referenced by Inventory offers.
Feed: task-based and scheduled bulk operations
Use the Feed wrapper when the workflow is file-driven rather than single-resource CRUD.
Task flow:
- create a task with
create_task() - upload its input file with
upload_file() - inspect the task with
get_task() - download results with
get_result_file()
Schedule flow:
- inspect schedule templates with
get_schedule_templates()orget_schedule_template() - create the recurring schedule with
create_schedule() - inspect or update it with
get_schedule()orupdate_schedule() - download the latest result file with
get_latest_result_file()
Helpers:
CreatedFeedResourceFeedFileDownloadextract_feed_resource_id()
Media: image, document, and video workflows
Use Media when you need hosted assets for listings.
Images:
create_image_from_file()create_image_from_path()create_image_from_url()get_image()
Documents:
create_document()upload_document()upload_document_from_path()get_document()wait_for_document()create_upload_and_wait_document()create_upload_and_wait_document_from_path()create_document_from_url_and_wait()
Videos:
create_video()upload_video()get_video()wait_for_video()create_upload_and_wait_video()create_upload_and_wait_video_from_path()
Helpers:
extract_resource_id()guess_media_content_type()VideoWorkflowResultDocumentWorkflowResult
Reference implementation: examples/media_workflows.py.
5. End-to-End Recipes
These are the shortest practical paths through the client for the most common seller tasks.
Recipe: read existing listed inventory data
Use this when you mainly want to inspect what is already listed or staged in eBay.
from ebay_client import EbayClient
from ebay_client.core.auth.models import EbayOAuthConfig
client = EbayClient(
EbayOAuthConfig(
client_id="your-client-id",
client_secret="your-client-secret",
default_scopes=["https://api.ebay.com/oauth/api_scope/sell.inventory.readonly"],
)
)
items = client.inventory.get_inventory_items(limit=50)
offers = client.inventory.get_offers(limit=50)
Methods involved:
get_inventory_items()get_offers()- optionally
get_inventory_item()andget_offer()for detail reads
Recipe: create an inventory item, create an offer, and publish it
Use this when you want the standard listing flow through the Inventory API.
from ebay_client import EbayClient
from ebay_client.core.auth.models import EbayOAuthConfig
from ebay_client.generated.inventory.models import InventoryItem, OfferDetailsWithKeys
client = EbayClient(
EbayOAuthConfig(
client_id="your-client-id",
client_secret="your-client-secret",
default_scopes=["https://api.ebay.com/oauth/api_scope/sell.inventory"],
)
)
client.inventory.create_or_replace_inventory_item(
"SKU-123",
InventoryItem(),
content_language="en-US",
)
offer = client.inventory.create_offer(OfferDetailsWithKeys())
client.inventory.publish_offer(offer.offerId)
Operational notes:
- you typically need business policy IDs and location data in place before the offer is valid
- the wrapper requires
content_languagefor the item write call because eBay expects it on several write endpoints - the exact request model fields depend on your marketplace and listing format
Recipe: receive Notification webhook events in FastAPI
Use the built-in webhook helpers instead of hand-parsing the signature format.
Flow:
- create a normal
EbayClient - build
WebhookPublicKeyResolverfromclient.notification.get_public_key - build
WebhookSignatureValidator - use
WebhookRequestHandlerfor both GET challenge and POST notification handling
Working example: examples/fastapi_notification_webhook.py.
Recipe: upload a document or video asset for listings
Use the Media wrapper helpers when you want the client to handle the create, upload, and polling loop for you.
from pathlib import Path
from ebay_client import EbayClient
from ebay_client.core.auth.models import EbayOAuthConfig
from ebay_client.generated.media.models import CreateDocumentRequest
client = EbayClient(
EbayOAuthConfig(
client_id="your-client-id",
client_secret="your-client-secret",
default_scopes=["https://api.ebay.com/oauth/api_scope/sell.inventory"],
)
)
result = client.media.create_upload_and_wait_document_from_path(
CreateDocumentRequest(
documentType="USER_GUIDE_OR_MANUAL",
languages=["en-US"],
),
Path("./manual.pdf"),
timeout_seconds=60.0,
)
print(result.document_id)
print(result.document.documentStatus)
Working example: examples/media_workflows.py.
Recipe: create a Feed task, upload its file, and download the result
Use this when the operation is file-based and asynchronous.
Flow:
- create the task with
create_task() - extract the returned
resource_id - upload the task input file with
upload_file() - poll
get_task()until the task reaches the state you expect - download the result with
get_result_file()
This wrapper already provides typed helpers for the file downloads through FeedFileDownload.
Working example: examples/feed_task_flow.py.
Recipe: dispute handling and evidence upload
Use the Fulfillment dispute methods only when you have the dispute-specific scope.
Flow:
- read the dispute with
get_payment_dispute() - upload the binary evidence file with
upload_evidence_file() - attach or update the evidence metadata with
add_evidence()orupdate_evidence() - contest or accept with
contest_payment_dispute()oraccept_payment_dispute()
Caveat: these calls go through the alternate apiz.ebay.com fulfillment base URL inside the wrapper.
Recipe: use the included examples directly
The repository now includes these runnable example scripts:
- examples/inventory_publish_flow.py: create or replace an inventory item, create an offer, and publish it
- examples/feed_task_flow.py: create a feed task, upload an input file, poll its status, and optionally save the result file
- examples/media_workflows.py: image, document, and video asset workflows
- examples/fastapi_notification_webhook.py: FastAPI-based challenge and notification handling
6. Working With Generated Models
The wrappers are intentionally thin. Request payloads and response types come from the generated Pydantic model packages.
Example pattern:
from ebay_client import EbayClient
from ebay_client.core.auth.models import EbayOAuthConfig
from ebay_client.generated.media.models import CreateDocumentRequest
client = EbayClient(
EbayOAuthConfig(
client_id="your-client-id",
client_secret="your-client-secret",
default_scopes=["https://api.ebay.com/oauth/api_scope/sell.inventory"],
)
)
result = client.media.create_upload_and_wait_document_from_path(
CreateDocumentRequest(
documentType="USER_GUIDE_OR_MANUAL",
languages=["en-US"],
),
"./manual.pdf",
)
For any wrapper method that takes a payload, look up the corresponding generated request model in the matching ebay_client.generated.<api>.models package.
7. Operational Notes
- The default token store is process-local and in-memory only.
- Empty
202and204responses are normalized by the shared transport so wrapper methods can returnNonecleanly for no-body success cases. - Multipart uploads are already handled by the transport and wrappers for Media, Feed, and dispute evidence uploads.
- Absolute URL handling is already built into the transport so wrappers can call alternate eBay hosts when required.
8. Validation and Regeneration
Run tests:
& .\.venv\Scripts\python.exe -m pytest
Regenerate model packages:
& .\.venv\Scripts\python.exe .\scripts\generate_clients.py
Generate just one API package:
& .\.venv\Scripts\python.exe .\scripts\generate_clients.py --api media
The generated models are written to ebay_client/generated/<api>/models.py.