cel APIcel.ro ↗
Access cel.ro product listings, prices, specs, reviews, and categories via API. Search products, browse categories, and fetch detailed product data.
What is the cel API?
The cel.ro API provides 4 endpoints for retrieving product and category data from Romania's electronics marketplace. Use search_products to query by keyword and get paginated results including price, availability, and image URLs, or use get_product_details to pull full specifications, seller info, reviews, and stock status for any individual product.
curl -X GET 'https://api.parse.bot/scraper/eb6de363-e59a-4604-9147-382ab2a6721d/search_products?query=samsung' \ -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 cel-ro-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.
"""
CEL.ro Product API - Parse Client
Search and extract product information from cel.ro, including pricing,
availability, and detailed specifications.
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Any, Optional, Dict, List
class ParseClient:
"""Client for interacting with the CEL.ro Scraper Parse API."""
def __init__(self, api_key: Optional[str] = None):
"""
Initialize the Parse API client.
Args:
api_key: API key for authentication. If not provided,
will look for PARSE_API_KEY environment variable.
"""
self.base_url = "https://api.parse.bot"
self.scraper_id = "eb6de363-e59a-4604-9147-382ab2a6721d"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError(
"API key not provided. Set PARSE_API_KEY environment variable "
"or pass api_key parameter."
)
def _call(
self, endpoint: str, method: str = "POST", **params
) -> Dict[str, Any]:
"""
Make a request to the Parse API.
Args:
endpoint: The API endpoint name
method: HTTP method (GET or POST)
**params: Query or body parameters
Returns:
Response data as dictionary
Raises:
requests.RequestException: If API request fails
"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json",
}
try:
if method.upper() == "GET":
response = requests.get(url, headers=headers, params=params)
elif method.upper() == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
except requests.RequestException as e:
raise requests.RequestException(f"API request failed: {str(e)}")
def get_categories(self) -> Dict[str, Any]:
"""
Retrieve the list of main product categories from cel.ro.
Returns:
Dictionary containing list of categories with name and slug
"""
return self._call("get_categories", method="GET")
def search_products(self, query: str, page: int = 1) -> Dict[str, Any]:
"""
Search for products by keyword on cel.ro.
Args:
query: Search keyword
page: Page number to retrieve (default: 1)
Returns:
Dictionary containing search results with product list
"""
return self._call(
"search_products", method="GET", query=query, page=page
)
def get_category_products(
self, category_slug: str, page: int = 1
) -> Dict[str, Any]:
"""
Retrieve products in a specific category slug.
Args:
category_slug: The category slug (e.g., 'laptop-laptopuri')
page: Page number to retrieve (default: 1)
Returns:
Dictionary containing products in the category
"""
return self._call(
"get_category_products",
method="GET",
category_slug=category_slug,
page=page,
)
def get_product_details(self, product_url: str) -> Dict[str, Any]:
"""
Get detailed information for a specific product by its URL.
Args:
product_url: Full product URL from cel.ro
Returns:
Dictionary containing detailed product information including
specifications, reviews, images, and pricing
"""
return self._call(
"get_product_details", method="GET", product_url=product_url
)
def format_price(price: Optional[float], currency: str = "LEI") -> str:
"""Format price for display."""
if price is None:
return "Price not available"
return f"{price:.2f} {currency}"
def print_product_summary(product: Dict[str, Any], index: int = 1) -> None:
"""Print a concise product summary."""
name = product.get("name", "Unknown")
price = product.get("price")
currency = product.get("currency", "LEI")
url = product.get("url", "")
print(f"\n {index}. {name}")
print(f" Price: {format_price(price, currency)}")
if url:
print(f" URL: {url[:70]}...")
def print_product_details(product: Dict[str, Any]) -> None:
"""Print detailed product information."""
print("\n" + "=" * 80)
print(f"📱 {product.get('name', 'Unknown')}")
print("=" * 80)
print(
f"\n💰 Price: {format_price(product.get('price'), product.get('currency', 'LEI'))}"
)
print(f"📦 Stock: {product.get('stock', 'Unknown')}")
print(f"🏪 Seller: {product.get('seller', 'Unknown')}")
specs = product.get("specifications", {})
if specs:
print("\n📋 Specifications:")
for key, value in specs.items():
print(f" • {key}: {value}")
images = product.get("images", [])
if images:
print(f"\n🖼️ Images: {len(images)} available")
reviews = product.get("reviews", [])
if reviews:
print(f"\n⭐ Reviews ({len(reviews)} total):")
for i, review in enumerate(reviews[:3], 1):
author = review.get("author", "Anonymous")
rating = review.get("rating", "N/A")
text = review.get("text", "")[:70]
date = review.get("date", "")
print(f" {i}. [{rating}★] {author} ({date})")
if text:
print(f" {text}...")
print("\n" + "=" * 80 + "\n")
def main():
"""Main workflow demonstrating practical API usage."""
# Initialize client
client = ParseClient()
print("\n" + "=" * 80)
print("🛍️ CEL.ro Product Research Tool")
print("=" * 80)
# Step 1: Get categories
print("\n📂 Step 1: Fetching available categories...")
try:
categories_response = client.get_categories()
categories = categories_response.get("data", {}).get("categories", [])
if not categories:
print("❌ No categories found")
return
print(f"✅ Found {len(categories)} categories")
for cat in categories[:5]:
print(f" • {cat['name']} (slug: {cat['slug']})")
except Exception as e:
print(f"❌ Error fetching categories: {e}")
return
# Step 2: Search for products
print("\n🔍 Step 2: Searching for 'Samsung Galaxy'...")
try:
search_response = client.search_products(query="Samsung Galaxy", page=1)
search_data = search_response.get("data", {})
products = search_data.get("products", [])
query = search_data.get("query", "")
print(f"✅ Found {len(products)} results for '{query}'")
if not products:
print(" No products found")
return
# Display first 3 search results
for i, product in enumerate(products[:3], 1):
print_product_summary(product, i)
if len(products) > 3:
print(f"\n ... and {len(products) - 3} more products")
except Exception as e:
print(f"❌ Error searching products: {e}")
return
# Step 3: Get detailed information for top 2 products
print("\n📖 Step 3: Fetching detailed information for top products...")
product_details_list = []
for idx, product in enumerate(products[:2], 1):
url = product.get("url", "")
name = product.get("name", "Unknown")
if url:
try:
print(f"\n [{idx}/2] Loading: {name[:50]}...")
details_response = client.get_product_details(product_url=url)
details = details_response.get("data", {})
product_details_list.append(details)
print(f" ✅ Specifications retrieved")
except Exception as e:
print(f" ⚠️ Could not load details: {e}")
# Display detailed information
if product_details_list:
print("\n" + "=" * 80)
print("📊 DETAILED PRODUCT COMPARISON")
print("=" * 80)
for i, details in enumerate(product_details_list, 1):
print_product_details(details)
# Compare prices
prices = [p.get("price") for p in product_details_list if p.get("price")]
if len(prices) >= 2:
price_diff = max(prices) - min(prices)
currency = product_details_list[0].get("currency", "LEI")
print(f"💡 Price difference: {format_price(price_diff, currency)}")
# Step 4: Browse a category
print("\n📂 Step 4: Browsing 'telefoane-mobile' category...")
try:
category_response = client.get_category_products(
category_slug="telefoane-mobile", page=1
)
category_data = category_response.get("data", {})
category_products = category_data.get("products", [])
category_name = category_data.get("category", "telefoane-mobile")
print(f"✅ Found {len(category_products)} products in '{category_name}'")
print("\n Top 5 products in this category:")
for i, product in enumerate(category_products[:5], 1):
print_product_summary(product, i)
if len(category_products) > 5:
print(f"\n ... and {len(category_products) - 5} more products")
# Price range analysis
prices = [
p.get("price") for p in category_products if p.get("price") is not None
]
if prices:
min_price = min(prices)
max_price = max(prices)
avg_price = sum(prices) / len(prices)
currency = category_products[0].get("currency", "LEI")
print(f"\n 💹 Price Analysis:")
print(f" Min: {format_price(min_price, currency)}")
print(f" Max: {format_price(max_price, currency)}")
print(f" Avg: {format_price(avg_price, currency)}")
except Exception as e:
print(f"❌ Error browsing category: {e}")
print("\n" + "=" * 80)
print("✅ Product research complete!")
print("=" * 80 + "\n")
if __name__ == "__main__":
main()Search for products by keyword on cel.ro. Returns paginated results with product names, prices, and URLs.
| Param | Type | Description |
|---|---|---|
| page | integer | Page number for pagination |
| queryrequired | string | Search keyword |
{
"type": "object",
"fields": {
"page": "string, current page number",
"query": "string, the search keyword used",
"products": "array of product objects with name, url, price, currency, image, availability, id"
},
"sample": {
"data": {
"page": "1",
"query": "samsung",
"products": [
{
"id": null,
"url": "https://www.cel.ro/samsung-galaxy-a57-5g-256gb-8gb-6-7-dual-sim-awesome-navy-pMCI0MzUpNCA-l/",
"name": "Samsung Galaxy A57 5G 256GB 8GB 6.7\" Dual SIM Awesome Navy",
"image": "https://s1.cel.ro/images/Products/2026/04/16/Telefon-mobil-Samsung-Galaxy-A57-Dual-SIM-8GB-RAM-256GB-5G-Awesome-Navy.jpg",
"price": 2199,
"currency": "LEI",
"availability": null
}
]
},
"status": "success"
}
}About the cel API
Endpoints and Data Coverage
The API covers four operations against cel.ro: listing all categories, browsing products within a category, searching by keyword, and fetching a single product's detail page. get_categories returns a flat list of category objects, each with a name and slug field. Those slugs feed directly into get_category_products as the category_slug parameter — for example, laptop-laptopuri or telefoane-mobile. Both the search and category endpoints return paginated arrays of product objects containing name, url, price, currency, image, availability, and id.
Product Details
get_product_details takes a full cel.ro product URL and returns the deepest data available: a specifications object with arbitrary key-value pairs (e.g. processor model, RAM, screen size), an images array of full-resolution URLs, a reviews array with per-review author, rating, text, and date fields, plus stock status, seller name, and price in LEI. Note that this endpoint requires solving a reCAPTCHA challenge on the source side, which can introduce additional latency compared to the category and search endpoints.
Pagination and Currency
Both search_products and get_category_products accept an optional page integer for stepping through results. The current page is echoed back in the page field of every response. All prices across the API are denominated in LEI (currency is always "LEI"), reflecting cel.ro's Romanian market focus. There is no cross-currency conversion in the response.
The cel API is a managed, monitored endpoint for cel.ro — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when cel.ro 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 cel.ro 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 price changes on specific electronics by polling
get_product_detailsfor target product URLs. - Build a Romanian electronics price comparison tool using
search_productsacross multiple keywords. - Populate a product catalog with specs and images by iterating
get_category_productswith category slugs fromget_categories. - Monitor stock availability fields from
get_product_detailsto alert when out-of-stock items return. - Aggregate customer review data (
author,rating,text,date) fromget_product_detailsfor sentiment analysis. - Discover the full category taxonomy of cel.ro using
get_categoriesfor navigation or site-mapping purposes. - Sync a local database with current cel.ro listings by paginating through category product results.
| 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 cel.ro have an official developer API?+
What does `get_product_details` return beyond what the listing endpoints provide?+
get_product_details returns the specifications object (arbitrary key-value product attributes), full images array, seller name, stock text, and a reviews array with per-review author, rating, text, and date. The listing and search endpoints only return name, url, price, currency, image, availability, and id.Why does `get_product_details` sometimes respond more slowly?+
Does the API return seller ratings, storefront pages, or multi-seller offer comparisons for a product?+
seller name string per product from get_product_details, but does not expose seller rating scores, multiple competing offers for the same product, or seller storefront data. You can fork this API on Parse and revise it to add an endpoint covering those fields.Can I retrieve subcategories or a nested category hierarchy?+
get_categories returns a flat list of category objects with name and slug. There is no hierarchy or parent-child relationship exposed in the response. You can fork this API on Parse and revise it to add subcategory nesting if the source structure supports it.