ebay_client/docs/usage-guide.md

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 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.

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_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:

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. 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() 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.

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.

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:

  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.

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:

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 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:

& .\.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.