Coursesu APIcoursesu.com ↗
Access Super U, Hyper U, and U Express Drive store locators, product catalogs, category trees, prices, and promotions via the coursesu.com API.
What is the Coursesu API?
The coursesu.com API exposes 6 endpoints covering French U-brand Drive stores: find stores by postcode or city, inspect a store's full product catalog via search_products or browse_category, navigate the category tree with list_categories, and retrieve per-store pricing and promotion data with get_product. All prices and availability are store-specific — there is no national catalog layer.
curl -X GET 'https://api.parse.bot/scraper/dcc0c43a-4358-493c-9ead-8a4cc5405848/find_stores?query=Rennes' \ -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 coursesu-com-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.
"""Walkthrough: coursesu.com SDK — find a store, search products, browse categories."""
from parse_apis.coursesu_com_api import CoursesU, SortOrder, InputNotFound
client = CoursesU()
# Find Drive stores near a French city.
result = client.stores.find(query="Rennes")
print(result.matched_location.city, result.matched_location.postcode)
print(f"{result.total_stores} stores found")
# Pick the nearest store and get full details.
nearest = result.stores[0]
print(nearest.store_name, nearest.distance_text)
store = nearest.details()
print(store.store_name, store.store_region)
# Search that store's products for milk, sorted by price.
for item in store.products.search(query="lait", sort=SortOrder.PRICE_ASC, limit=5):
print(item.name, item.regular_price, item.availability)
# Drill into one product's full detail page.
hit = store.products.search(query="beurre", limit=1).first()
if hit is not None:
product = hit.details()
print(product.name, product.brand, product.ean)
print(product.description[:120] if product.description else "")
if product.promotion is not None:
print(f"Promo: {product.promotion.label}")
# List top-level categories, then browse one.
top_cats = store.categories.list(limit=5).list()
for cat in top_cats:
print(cat.name, cat.category_id)
if top_cats:
for p in store.products.browse(category_id=top_cats[0].category_id, limit=3):
print(p.name, p.price_per_unit.value, p.price_per_unit.unit if p.price_per_unit else "")
# Point-lookup by store ID when already known.
try:
known = client.stores.get(store_id="37910")
print(known.store_name, known.store_url)
except InputNotFound:
print("Store not found")
print("exercised: stores.find / stores.get / products.search / products.browse / categories.list / product.details")
Finds U stores offering click-and-collect around a French postcode or city name. The free-text query is resolved to a locality first (the matched locality and the other candidate localities are returned), then all stores the site lists for that locality come back in one call, nearest first, with the store ID to use with the other endpoints, the store name, postal address, distance, the services offered (drive = car pick-up, pickup_point = relay / walk-in pick-up point, walk_in_drive, home_delivery) and the next available pick-up slot per service. An unrecognised locality returns an empty store list with matched_location null. Two round trips per call; not paginated.
| Param | Type | Description |
|---|---|---|
| queryrequired | string | French postcode (5 digits) or city name, as typed into the site's store locator (one shape: 75015). |
{
"type": "object",
"fields": {
"query": "the query as received",
"stores": "array of store records: store_id (string, input for the other endpoints), store_name, address, distance_text (site wording), distance_km (number, converted from metres when the site shows metres), services (array of service codes), delivery_options (array of {mode: site mode code, service, label, next_slot_start, next_slot_end} local ISO datetimes)",
"total_stores": "integer count of stores the site reports for the locality (equals the length of stores)",
"last_checked_at": "UTC ISO-8601 timestamp of this lookup",
"other_locations": "array of alternative {postcode, city} candidates the site proposed for the query",
"matched_location": "object {postcode, city} the query resolved to, or null when the site knows no such locality"
},
"sample": {
"data": {
"query": "Rennes",
"stores": [
{
"address": "27 rue poullain duparc, 44 bd de la liberte, 35000 Rennes",
"services": [
"drive"
],
"store_id": "37910",
"store_name": "U Express - Rennes Liberte",
"distance_km": 0.824,
"distance_text": "824 m",
"delivery_options": [
{
"mode": "RETRAIT",
"label": null,
"service": "drive",
"next_slot_end": "2026-09-21T10:00:00",
"next_slot_start": "2026-09-21T09:00:00"
}
]
}
],
"total_stores": 42,
"last_checked_at": "2026-09-20T14:42:45Z",
"other_locations": [
{
"city": "Rennes",
"postcode": "35200"
},
{
"city": "Rennes",
"postcode": "35700"
}
],
"matched_location": {
"city": "Rennes",
"postcode": "35000"
}
},
"status": "success"
}
}About the Coursesu API
Store Discovery and Selection
Start with find_stores, passing a 5-digit French postcode or a city name as query. The response includes an array of stores records — each with store_id, store_name, address, and distance_text — alongside matched_location (the resolved {postcode, city} object) and other_locations for alternative candidates the site proposed. Pass a store_id to get_store to validate the selection and retrieve store_name, store_region (the regional U cooperative), store_url, and page_title.
Product Search and Category Browsing
search_products accepts query, store_id, and optional page (1-based, 18 results per page) and sort parameters. Each product record includes product_id, name, brand, ean, a category object with a path array of {category_id, name} nodes, and a quantity object parsed from the product name (value, unit, pack_count, unit_size). has_more and total_results support pagination. browse_category works the same way but scopes results to a specific category_id; it also returns subcategories and accepts a promotions_only boolean to filter to on-promotion items only.
Category Tree
list_categories returns the store's top-level departments when called without category_id, each with a 16-digit category_id, name, url, and level. Pass one of those IDs back to get level-2 and level-3 subcategories — level-2 records include a nested subcategories array. The other_menu_entries field (top level only) lists menu items that don't map to a browsable 16-digit category ID. parent_category_id is null at the top level and set to the parent's ID for child calls.
Product Detail
get_product takes store_id and product_id and returns the full detail view: name, brand, ean, images array, image_url, rating, regular_price and promotional_price in EUR, a promotion object (type, label), parsed quantity, net_weight, and the category path. Prices and promotion status reflect the selected store only.
The Coursesu API is a managed, monitored endpoint for coursesu.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when coursesu.com 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 coursesu.com 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?+
- Build a French grocery price comparison tool using regular_price and promotional_price fields across multiple Drive stores.
- Monitor promotion availability in specific U Drive stores using browse_category with promotions_only=true.
- Automate weekly Drive order basket assembly by querying search_products for recurring items by keyword.
- Map U Drive store coverage for a given region by iterating find_stores across postcodes and collecting store_id and address fields.
- Sync a product catalog to an internal database using list_categories to walk the full category tree and browse_category to enumerate all products per node.
- Track EAN-level product availability across different regional U cooperatives using store_region from get_store combined with get_product data.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.