Back Market APIbackmarket.fr ↗
Search refurbished electronics on Back Market France, retrieve product details with variants and pricing, and fetch customer reviews via 3 structured endpoints.
What is the Back Market API?
The Back Market France API covers 3 endpoints for querying the Back Market France catalog: search by keyword, fetch full product details by UUID or URL, and retrieve customer reviews. The search_products endpoint returns paginated results with price, rating, and direct product links. get_product_details exposes condition, storage, and battery variants alongside availability status and original retail price for any listed product.
curl -X GET 'https://api.parse.bot/scraper/25ea2afe-3b30-4695-b04b-83a719b17b4d/get_product_details?product_id=%3Cproduct_uuid%3E&product_url=https%3A%2F%2Fwww.backmarket.fr%2Ffr-fr%2Fp%2Fiphone-15%2F%3Cproduct_uuid%3E' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace backmarket-fr-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""
Back Market Parse API Client
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Optional, Any, Dict, List
class ParseClient:
"""Client for interacting with the Back Market API through Parse."""
def __init__(self, api_key: Optional[str] = None):
self.base_url = "https://api.parse.bot"
self.scraper_id = "25ea2afe-3b30-4695-b04b-83a719b17b4d"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError("API key not provided and PARSE_API_KEY not set")
def _call(self, endpoint: str, method: str = "POST", **params) -> Dict[str, Any]:
"""Make API call to Parse endpoint.
Args:
endpoint: The API endpoint name
method: HTTP method (GET or POST)
**params: Query/body parameters
Returns:
JSON response as dictionary
"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json"
}
if method == "GET":
response = requests.get(url, headers=headers, params=params)
elif method == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
def search_products(self, query: str, page: int = 0, limit: int = 31) -> Dict[str, Any]:
"""Search for products on Back Market by keyword.
Args:
query: Search keyword (e.g., 'iPhone 15')
page: Page number (default: 0)
limit: Number of results per page (default: 31)
Returns:
Dictionary containing products list, total_hits, page, and nbPages
"""
return self._call("search_products", method="GET", query=query, page=page, limit=limit)
def get_product_details(self, product_url: Optional[str] = None,
product_id: Optional[str] = None) -> Dict[str, Any]:
"""Extract detailed product information from a Back Market product URL or UUID.
Args:
product_url: Full Back Market product URL
product_id: Product UUID
Returns:
Dictionary containing uuid, title, brand, model, pricing, rating, variants, etc.
"""
params = {}
if product_url:
params["product_url"] = product_url
if product_id:
params["product_id"] = product_id
if not params:
raise ValueError("Either product_url or product_id must be provided")
return self._call("get_product_details", method="GET", **params)
def get_product_reviews(self, product_url: Optional[str] = None,
product_id: Optional[str] = None) -> Dict[str, Any]:
"""Retrieve customer reviews for a product.
Args:
product_url: Full Back Market product page URL
product_id: Product UUID
Returns:
Dictionary containing average_rating, review_count, reviews list, and page
"""
params = {}
if product_url:
params["product_url"] = product_url
if product_id:
params["product_id"] = product_id
if not params:
raise ValueError("Either product_url or product_id must be provided")
return self._call("get_product_reviews", method="GET", **params)
def format_price(price: Optional[float]) -> str:
"""Format price with euro symbol."""
if price is None:
return "N/A"
return f"€{price:,.2f}"
def format_rating(rating: float, review_count: int) -> str:
"""Format rating with star visualization."""
full_stars = int(rating)
half_star = "½" if rating % 1 >= 0.5 else ""
empty_stars = 5 - full_stars - (1 if half_star else 0)
stars = "★" * full_stars + half_star + "☆" * empty_stars
return f"{stars} {rating:.2f}/5.0 ({review_count:,} reviews)"
def display_product_summary(product: Dict[str, Any]) -> None:
"""Display a summary of a product from search results."""
print(f"\n📱 {product.get('name', 'Unknown Product')}")
print(f" Brand: {product.get('brand', 'N/A')} | Model: {product.get('model', 'N/A')}")
print(f" Price: {format_price(product.get('price'))} ", end="")
original = product.get('original_price')
current = product.get('price', 0)
if original and original > current:
savings = ((original - current) / original) * 100
print(f"(Save {savings:.0f}% from {format_price(original)})")
else:
print()
print(f" {format_rating(product.get('rating', 0), product.get('review_count', 0))}")
def display_detailed_analysis(product_id: str, client: ParseClient) -> None:
"""Fetch and display detailed analysis of a product."""
try:
# Get product details
details = client.get_product_details(product_id=product_id)
data = details.get('data', {})
print(f"\n 📋 Product Details:")
print(f" • UUID: {data.get('uuid')}")
print(f" • Title: {data.get('title')}")
print(f" • Starting Price: {format_price(data.get('starting_price'))}")
availability = data.get('availability', {})
in_stock = "✓ In Stock" if availability.get('in_stock') else "✗ Out of Stock"
can_add = "✓ Addable to Cart" if availability.get('can_add_to_cart') else "✗ Not Available"
print(f" • {in_stock} | {can_add}")
# Display variant options
variants = data.get('variants', [])
if variants:
print(f" • Available Variants:")
for variant in variants:
label = variant.get('label', 'Unknown')
items = variant.get('items', [])
if items:
first_item = items[0]
item_label = first_item.get('label', 'N/A')
price_info = first_item.get('price', {})
price = price_info.get('amount') if isinstance(price_info, dict) else price_info
print(f" - {label}: {item_label} ({format_price(float(price) if price else 0)})")
# Get and display reviews
print(f"\n 💬 Customer Reviews:")
reviews_response = client.get_product_reviews(product_id=product_id)
reviews_data = reviews_response.get('data', {})
avg_rating = reviews_data.get('average_rating', 0)
review_count = reviews_data.get('review_count', 0)
reviews = reviews_data.get('reviews', [])
print(f" Average Rating: {format_rating(avg_rating, review_count)}")
if reviews:
print(f" Top Reviews:")
for idx, review in enumerate(reviews[:3], 1):
rating = review.get('rating', 0)
author = review.get('author', 'Anonymous')
comment = review.get('comment', 'No comment')
if len(comment) > 80:
comment = comment[:80] + "..."
star_rating = "★" * rating + "☆" * (5 - rating)
print(f" {idx}. [{star_rating}] {author}")
print(f" '{comment}'")
except requests.exceptions.RequestException as e:
print(f" ⚠️ Error fetching details: {str(e)}")
except (KeyError, ValueError) as e:
print(f" ⚠️ Unexpected response format: {str(e)}")
def main():
"""Practical workflow: search for products and analyze top results with details and reviews."""
client = ParseClient()
print("\n" + "=" * 80)
print("🛍️ BACK MARKET PRODUCT ANALYZER".center(80))
print("=" * 80)
# Step 1: Search for products
search_query = "iPhone 15"
print(f"\n🔍 Searching for '{search_query}' on Back Market France...")
search_results = client.search_products(query=search_query, limit=5)
if search_results.get('status') != 'success':
print("❌ Search failed")
return
search_data = search_results.get('data', {})
total_hits = search_data.get('total_hits', 0)
products = search_data.get('products', [])
total_pages = search_data.get('nbPages', 1)
print(f"✓ Found {total_hits} total products across {total_pages} pages")
print(f"✓ Analyzing top {len(products)} results...\n")
# Step 2: Analyze each product - get details and reviews
for idx, product in enumerate(products, 1):
print("\n" + "-" * 80)
print(f"RESULT {idx}/{len(products)}")
print("-" * 80)
display_product_summary(product)
product_id = product.get('uuid')
if product_id:
display_detailed_analysis(product_id, client)
print("\n" + "=" * 80)
print("✓ Analysis Complete!".center(80))
print("=" * 80 + "\n")
if __name__ == "__main__":
main()Extract detailed product information from a Back Market product UUID. Returns pricing, brand, model, images, available variants (condition, storage, battery), and availability status.
| Param | Type | Description |
|---|---|---|
| product_id | string | Product UUID (e.g. 'a8517119-6ed0-4c6f-8799-22f95658bc19'). Either product_id or product_url must be provided. |
| product_url | string | Full Back Market product URL containing a UUID in the path (e.g. 'https://www.backmarket.fr/fr-fr/p/iphone-15/a8517119-6ed0-4c6f-8799-22f95658bc19'). Either product_id or product_url must be provided. |
{
"type": "object",
"fields": {
"uuid": "string product UUID",
"brand": "string brand name",
"model": "string model name",
"title": "string product title",
"images": "array of image URLs",
"rating": "number average customer rating",
"variants": "array of picker groups (condition, battery, storage options)",
"availability": "object with in_stock and can_add_to_cart booleans",
"review_count": "integer total number of reviews",
"original_price": "number or null original retail price",
"starting_price": "string or number lowest available price"
},
"sample": {
"data": {
"uuid": "a8517119-6ed0-4c6f-8799-22f95658bc19",
"brand": "Apple",
"model": "iPhone 15",
"title": "iPhone 15Bleu • 128 Go • SIM physique + eSIM",
"images": [
"https://d2e6ccujb3mkqf.cloudfront.net/a8517119-6ed0-4c6f-8799-22f95658bc19-1_4afffbc4-dcec-45c2-a6ab-fb0b22f2d9b4.jpg"
],
"rating": 4.58,
"variants": [
{
"id": "grades",
"items": [
{
"label": "Très bon état",
"price": {
"amount": "396.00",
"currency": "EUR"
}
}
],
"label": "État"
}
],
"availability": {
"in_stock": false,
"can_add_to_cart": false
},
"review_count": 29889,
"original_price": null,
"starting_price": "396.00"
},
"status": "success"
}
}About the Back Market API
Product Search
The search_products endpoint accepts a required query string (e.g. 'iPhone 15', 'MacBook Pro') and returns paginated results. Each product object in the products array includes name, uuid, brand, model, price, original_price, rating, review_count, image, and url. Pagination is 0-indexed via the page parameter, and nbPages plus total_hits let you iterate the full result set.
Product Details
get_product_details accepts either a product_id (UUID string) or a full product_url containing a UUID in the path — at least one must be provided. The response includes the product title, brand, model, an images array, aggregate rating, review_count, and original_price when available. The variants field returns an array of picker groups covering condition (e.g. Fair/Good/Excellent), storage capacity, and battery health options. The availability object exposes in_stock and can_add_to_cart booleans for the current listing state.
Customer Reviews
get_product_reviews accepts the same product_id or product_url inputs as the detail endpoint. It returns up to 7 top reviews, each with an integer rating, author name, and comment text. Alongside the review array, the response includes average_rating (out of 5) and review_count for the full aggregate totals, even though the reviews array itself is capped at 7 entries per call.
The Back Market API is a managed, monitored endpoint for backmarket.fr — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when backmarket.fr changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official backmarket.fr API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Track refurbished iPhone prices across condition variants (Fair/Good/Excellent) using
variantsfromget_product_details. - Build a price-comparison tool that pulls
original_pricevs.priceto show savings on refurbished electronics. - Monitor
availability.in_stockstatus for specific product UUIDs to alert users when a listing comes back in stock. - Aggregate
average_ratingandreview_countdata across search results to rank the best-reviewed refurbished laptops. - Extract customer sentiment from
commentfields inget_product_reviewsfor a specific product. - Paginate through
search_productsresults to build a full catalog snapshot of Back Market France's refurbished inventory. - Compare
batteryvariants for refurbished phones to surface listings with the best battery condition at a given price point.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does Back Market have an official public developer API?+
What does `get_product_details` return beyond basic pricing?+
price and original_price, the endpoint returns a variants array that breaks down available picker options for condition (e.g. Fair, Good, Excellent), storage capacity, and battery health. It also returns an availability object with in_stock and can_add_to_cart booleans, plus an images array and aggregate rating and review_count.How many reviews does `get_product_reviews` return per call?+
review_count and average_rating fields reflect the full aggregate totals for the product, but paginating through all reviews beyond those 7 is not currently supported. You can fork this API on Parse and revise it to add deeper review pagination.