Add usage guide for eBay REST Client to enhance documentation

This commit is contained in:
claudi 2026-04-07 11:23:09 +02:00
parent c17cc3fbbc
commit 2c6bd35ebb
2 changed files with 369 additions and 0 deletions

View file

@ -18,6 +18,8 @@ Implemented API domains:
The public entry point is `EbayClient`, which wires all six wrappers behind one shared transport and one shared token store.
For a workflow-oriented guide with setup patterns, scope planning, and common usage recipes, see [docs/usage-guide.md](docs/usage-guide.md).
## Project Layout
- `ebay_client/client.py`: top-level `EbayClient` facade

367
docs/usage-guide.md Normal file
View file

@ -0,0 +1,367 @@
# 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.
### 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`.
### 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`.
## 5. 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.
## 6. 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.
## 7. 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`.