529 lines
18 KiB
Markdown
529 lines
18 KiB
Markdown
# 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 `EbayClient` directly or `EbayOAuthClient` too?
|
|
- 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.
|
|
|
|
```python
|
|
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.
|
|
|
|
```python
|
|
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_scopes` are mainly the fallback used when you explicitly call OAuth methods without passing scopes yourself.
|
|
|
|
## 3. Top-Level Client Map
|
|
|
|
`EbayClient` exposes these subclients:
|
|
|
|
- `client.notification`
|
|
- `client.inventory`
|
|
- `client.fulfillment`
|
|
- `client.account`
|
|
- `client.feed`
|
|
- `client.media`
|
|
|
|
Use the generated model packages for request and response types:
|
|
|
|
- `ebay_client.generated.notification.models`
|
|
- `ebay_client.generated.inventory.models`
|
|
- `ebay_client.generated.fulfillment.models`
|
|
- `ebay_client.generated.account.models`
|
|
- `ebay_client.generated.feed.models`
|
|
- `ebay_client.generated.media.models`
|
|
|
|
## 4. Common Workflows
|
|
|
|
This section maps typical seller workflows to wrapper methods.
|
|
|
|
Quick source jumps:
|
|
|
|
- facade: [ebay_client/client.py](../ebay_client/client.py)
|
|
- notification wrapper: [ebay_client/notification/client.py](../ebay_client/notification/client.py)
|
|
- inventory wrapper: [ebay_client/inventory/client.py](../ebay_client/inventory/client.py)
|
|
- fulfillment wrapper: [ebay_client/fulfillment/client.py](../ebay_client/fulfillment/client.py)
|
|
- account wrapper: [ebay_client/account/client.py](../ebay_client/account/client.py)
|
|
- feed wrapper: [ebay_client/feed/client.py](../ebay_client/feed/client.py)
|
|
- media wrapper: [ebay_client/media/client.py](../ebay_client/media/client.py)
|
|
- FastAPI webhook example: [examples/fastapi_notification_webhook.py](../examples/fastapi_notification_webhook.py)
|
|
- media workflows example: [examples/media_workflows.py](../examples/media_workflows.py)
|
|
- inventory publish example: [examples/inventory_publish_flow.py](../examples/inventory_publish_flow.py)
|
|
- feed task example: [examples/feed_task_flow.py](../examples/feed_task_flow.py)
|
|
|
|
### Notification: manage webhook subscriptions
|
|
|
|
Typical flow:
|
|
|
|
1. inspect available topics with `get_topics()`
|
|
2. create or update a destination with `create_destination()` or `update_destination()`
|
|
3. create the subscription with `create_subscription()`
|
|
4. optionally attach filters with `create_subscription_filter()`
|
|
5. 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:
|
|
|
|
1. answer the GET challenge with `WebhookRequestHandler.handle_challenge()`
|
|
2. resolve the public key through `WebhookPublicKeyResolver`
|
|
3. verify the POST body with `WebhookSignatureValidator`
|
|
4. dispatch the parsed `WebhookEventEnvelope`
|
|
|
|
Reference implementation: [examples/fastapi_notification_webhook.py](../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:
|
|
|
|
1. create or replace the inventory item with `create_or_replace_inventory_item()`
|
|
2. configure location data if needed with `create_inventory_location()` or `update_inventory_location()`
|
|
3. create the offer with `create_offer()`
|
|
4. 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:
|
|
|
|
1. read orders with `get_orders()` or `get_order()`
|
|
2. create shipment details with `create_shipping_fulfillment()`
|
|
3. inspect resulting records with `get_shipping_fulfillments()` or `get_shipping_fulfillment()`
|
|
|
|
Helper returned by create:
|
|
|
|
- `CreatedShippingFulfillment`, which includes the `Location` header 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.finances` scope 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.dispute` scope
|
|
- 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:
|
|
|
|
1. create a task with `create_task()`
|
|
2. upload its input file with `upload_file()`
|
|
3. inspect the task with `get_task()`
|
|
4. download results with `get_result_file()`
|
|
|
|
Schedule flow:
|
|
|
|
1. inspect schedule templates with `get_schedule_templates()` or `get_schedule_template()`
|
|
2. create the recurring schedule with `create_schedule()`
|
|
3. inspect or update it with `get_schedule()` or `update_schedule()`
|
|
4. download the latest result file with `get_latest_result_file()`
|
|
|
|
Helpers:
|
|
|
|
- `CreatedFeedResource`
|
|
- `FeedFileDownload`
|
|
- `extract_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()`
|
|
- `VideoWorkflowResult`
|
|
- `DocumentWorkflowResult`
|
|
|
|
Reference implementation: [examples/media_workflows.py](../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.
|
|
|
|
```python
|
|
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()` and `get_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.
|
|
|
|
```python
|
|
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_language` for 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:
|
|
|
|
1. create a normal `EbayClient`
|
|
2. build `WebhookPublicKeyResolver` from `client.notification.get_public_key`
|
|
3. build `WebhookSignatureValidator`
|
|
4. use `WebhookRequestHandler` for both GET challenge and POST notification handling
|
|
|
|
Working example: [examples/fastapi_notification_webhook.py](../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.
|
|
|
|
```python
|
|
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](../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:
|
|
|
|
1. create the task with `create_task()`
|
|
2. extract the returned `resource_id`
|
|
3. upload the task input file with `upload_file()`
|
|
4. poll `get_task()` until the task reaches the state you expect
|
|
5. 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](../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:
|
|
|
|
1. read the dispute with `get_payment_dispute()`
|
|
2. upload the binary evidence file with `upload_evidence_file()`
|
|
3. attach or update the evidence metadata with `add_evidence()` or `update_evidence()`
|
|
4. contest or accept with `contest_payment_dispute()` or `accept_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](../examples/inventory_publish_flow.py): create or replace an inventory item, create an offer, and publish it
|
|
- [examples/feed_task_flow.py](../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](../examples/media_workflows.py): image, document, and video asset workflows
|
|
- [examples/fastapi_notification_webhook.py](../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:
|
|
|
|
```python
|
|
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 `202` and `204` responses are normalized by the shared transport so wrapper methods can return `None` cleanly 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:
|
|
|
|
```powershell
|
|
& .\.venv\Scripts\python.exe -m pytest
|
|
```
|
|
|
|
Regenerate model packages:
|
|
|
|
```powershell
|
|
& .\.venv\Scripts\python.exe .\scripts\generate_clients.py
|
|
```
|
|
|
|
Generate just one API package:
|
|
|
|
```powershell
|
|
& .\.venv\Scripts\python.exe .\scripts\generate_clients.py --api media
|
|
```
|
|
|
|
The generated models are written to `ebay_client/generated/<api>/models.py`.
|