API Reference
Programmatic access to ShopList — build bots, integrations, and automations.
Authentication
All requests require an API key via the X-API-Key header:
X-API-Key: YOUR_API_KEY
Most endpoints also need a user_id query parameter to identify the acting user. Contact the admin for your API key and user ID.
https://shopping.sprcon.de/api/
Lists
GET /api/lists/?user_id={id}
Returns all shopping lists the user owns, is shared with, or belongs to via group.
{
"lists": [
{
"id": 1,
"name": "Weekly Groceries",
"owner": 1,
"group": null,
"created_at": "2026-01-15T10:30:00Z",
"items": [ ... ],
"items_count": 5
}
]
}
POST /api/lists/create/?user_id={id}
Create a new shopping list. Send a JSON body.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | List name (max 100 chars) |
group_id | integer | no | Group to associate list with |
# Personal list
{ "name": "My Shopping List" }
# Group list
{ "name": "Family Groceries", "group_id": 2 }
Returns 201 Created with the list object. User must be member of specified group.
DELETE /api/lists/{id}/delete/?user_id={id}
Delete a personal list. Only the owner can delete, and only personal lists (no group).
{ "message": "List deleted successfully" }
POST /api/lists/{id}/leave/?user_id={id}
Leave a shared or group list. Removes the user from the list.
- If you're the owner, ownership transfers to another member
- If no members remain, the list is deleted
- Cannot leave personal lists (use delete instead)
# Success
{ "message": "Successfully left the list" }
# List deleted when no members remain
{ "message": "List deleted as no members remain" }
Items
GET /api/lists/{list_id}/items/?user_id={id}
Returns all items in a shopping list.
{
"items": [
{
"id": 1,
"shopping_list": 1,
"name": "Milk",
"category": { "id": 2, "name": "Dairy" },
"amount": 2,
"max_price": "3.50",
"buy_until": "2026-02-15",
"link": null,
"created_at": "2026-02-10T14:00:00Z",
"is_bought": false
}
]
}
POST /api/lists/{list_id}/items/create/?user_id={id}
Add a new item to a list. Send a JSON body.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Item name (max 100 chars) |
amount | integer | no | Quantity (default: 1) |
category_id | integer | no | Category ID |
max_price | decimal | no | Maximum price |
buy_until | YYYY-MM-DD | no | Purchase deadline |
link | URL | no | Product link |
Returns 201 Created with the item object.
PATCH /api/items/{item_id}/update/?user_id={id}
Update an item. Send only fields to change.
{ "amount": 3, "max_price": "4.00" }
DELETE /api/items/{item_id}/delete/?user_id={id}
Delete an item.
{ "message": "Item deleted successfully" }
POST /api/items/{item_id}/toggle/?user_id={id}
Toggle is_bought status. Returns the updated item.
Categories
GET /api/categories/
List all categories. No user_id required.
{
"categories": [
{ "id": 1, "name": "Electronics" },
{ "id": 2, "name": "Groceries" },
{ "id": 3, "name": "Household" }
]
}
POST /api/categories/create/?user_id={id}
Create a new category. Send a JSON body.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Category name (must be unique) |
{ "name": "Books" }
Returns 201 Created with the category object, or 400 if category already exists.
Shops
GET /api/shops/
List all shops and their categories. No user_id required.
{
"shops": [
{
"id": 1,
"name": "Amazon",
"url": "https://amazon.de",
"categories": [
{ "id": 1, "name": "Electronics" },
{ "id": 3, "name": "Household" }
]
}
]
}
Groups
GET /api/groups/?user_id={id}
List all groups the user belongs to.
{
"groups": [
{
"id": 1,
"name": "Household",
"members": [1, 2, 3],
"created_at": "2026-01-01T00:00:00Z"
}
]
}
Bulk Check
GET /api/bulk-check/?user_id={id}
Scans all unbought items across all accessible lists. Groups by category and returns categories with 2+ items — potential bulk order opportunities.
{
"bulk_opportunities": {
"Electronics": [
{ "id": 5, "name": "USB-C Cable", "list_name": "Office", "amount": 3, "max_price": "8.00" },
{ "id": 12, "name": "HDMI Adapter", "list_name": "Living Room", "amount": 1, "max_price": null }
]
}
}
Errors
All errors return JSON with an error field:
| Status | Meaning |
|---|---|
400 | Bad request — missing params, invalid JSON |
401 | Invalid or missing API key |
403 | No access to this resource |
404 | Not found |
405 | Wrong HTTP method |
Examples
curl
# List your shopping lists
curl -H "X-API-Key: YOUR_KEY" \
"https://shopping.sprcon.de/api/lists/?user_id=1"
# Create a personal list
curl -X POST \
-H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "My New List"}' \
"https://shopping.sprcon.de/api/lists/create/?user_id=1"
# Create a group list
curl -X POST \
-H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Family List", "group_id": 2}' \
"https://shopping.sprcon.de/api/lists/create/?user_id=1"
# Leave a list
curl -X POST -H "X-API-Key: YOUR_KEY" \
"https://shopping.sprcon.de/api/lists/3/leave/?user_id=1"
# Delete a personal list
curl -X DELETE -H "X-API-Key: YOUR_KEY" \
"https://shopping.sprcon.de/api/lists/5/delete/?user_id=1"
# Add an item
curl -X POST \
-H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Bananas", "amount": 6}' \
"https://shopping.sprcon.de/api/lists/1/items/create/?user_id=1"
# List categories
curl -H "X-API-Key: YOUR_KEY" \
"https://shopping.sprcon.de/api/categories/"
# Create category
curl -X POST \
-H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Books"}' \
"https://shopping.sprcon.de/api/categories/create/?user_id=1"
# Toggle bought
curl -X POST -H "X-API-Key: YOUR_KEY" \
"https://shopping.sprcon.de/api/items/3/toggle/?user_id=1"
# Check bulk opportunities
curl -H "X-API-Key: YOUR_KEY" \
"https://shopping.sprcon.de/api/bulk-check/?user_id=1"
Python
import requests
BASE = "https://shopping.sprcon.de/api"
HEADERS = {"X-API-Key": "YOUR_KEY"}
USER = {"user_id": "1"}
# Get all lists
lists = requests.get(f"{BASE}/lists/", headers=HEADERS, params=USER).json()
# Create a personal list
new_list = requests.post(
f"{BASE}/lists/create/",
headers={**HEADERS, "Content-Type": "application/json"},
params=USER,
json={"name": "My Shopping List"}
).json()
# Create a category
category = requests.post(
f"{BASE}/categories/create/",
headers={**HEADERS, "Content-Type": "application/json"},
params=USER,
json={"name": "Electronics"}
).json()
# Add an item
requests.post(
f"{BASE}/lists/1/items/create/",
headers={**HEADERS, "Content-Type": "application/json"},
params=USER,
json={"name": "Coffee", "amount": 1, "category_id": 3}
)
# Leave a list
requests.post(f"{BASE}/lists/2/leave/", headers=HEADERS, params=USER)
# Toggle bought
requests.post(f"{BASE}/items/5/toggle/", headers=HEADERS, params=USER)