The Spisko REST API
The Spisko REST API is the one the app itself uses to change your items, lists and stores. This page lists its endpoints, the fields each one takes, and what comes back. To connect a script or an AI assistant, the MCP server is the easier way in.
Before you start
The REST API takes the access token of a signed-in Spisko session, which lasts an hour. Personal access tokens don't work here: they're for the MCP server, which covers lists, items and stock, and suits scripts and assistants better.
- Base URL:
https:// spisko.com/ api - Format: JSON in and JSON out, with
Content-Type: application/on every request that has a body.json - Auth:
Authorization: Bearer <access_on every request. Without a valid token the answer istoken> 401. - Whose data: what your account can see in the app. That is your own items, lists and stores, and the ones shared with you in a space. Something you can’t see answers
404.
curl https://spisko.com/api/items \
-H "Authorization: Bearer $ACCESS_TOKEN"Answers and errors
A read answers 200 with the record or a list of them. A create answers 201 with what it made, and an update 200 with the record as it is now.
An error answers with { "error": "…" }, in English. When the app explains an error in its own words, a code comes with it:
400: the body isn’t JSON, or a field is missing or wrong. The message names the field.401: no token, or one that has expired.403: not yours to change.plus_means the change needs Spisko Plus.required space_,cap member_andcap store_mean a free account’s limit: one space, six people in it, three stores.cap 404: not there, or not visible to you.409: it already exists, or a request with the sameIdempotency-Keyis still running.
Retrying safely. Writes to items, categories, lists and what’s on them take an optional Idempotency-Key header, a UUID you make. Send the same key again (after a timeout, say) and you get the first answer back instead of the change happening twice. Keys are kept for seven days.
curl -X POST https://spisko.com/api/shopping-lists/$LIST_ID/items \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "name": "Bananas", "quantity": 3 }'Items
Items are your inventory: what you keep at home, how much you have (current_) and how much you like to keep (goal_).
GET
/api/itemsYour items, newest first, each with its categories.
POST
/api/itemsAdd an item.
Body
name*,description,current_,quantity goal_,quantity unit,barcodeGET
/api/items/{id}One item, with its categories.
PATCH
/api/items/{id}Change an item: any of the fields above, at least one.
PATCH
/api/items/{id}/quantityChange how much there is.
deltaadds or takes away (it can be negative); the other two set a value.Body
delta,current_,quantity goal_(at least one)quantity DELETE
/api/items/{id}Remove an item from your inventory. Answers
{ "deleted": true, "id": … }.POST
/api/items/{id}/restoreBring back a removed item, the same one, with its categories.
POST
/api/items/{id}/categoriesPut an item in a category.
Body
category_*id DELETE
/api/items/{id}/categories/{categoryId}Take an item out of a category.
GET
/api/shopping/suggestionsItems running low, down to half their goal quantity or less: what to buy next.
Categories
Categories group the inventory: where things are kept, or what they are.
GET
/api/categoriesYour categories.
POST
/api/categoriesAdd a category.
typesays what kind it is, for examplestorageorroom.Body
name*,type*,is_shareable PATCH
/api/categories/{id}Rename or retype a category.
DELETE
/api/categories/{id}Delete a category.
Shopping lists
A list’s kind decides what finishing it does: permanent (bought things come off the list), recurring (everything stays, unticked for next time) or adhoc (the list is deleted and the inventory isn’t touched). space_ shares a list with a space; null makes it private again.
GET
/api/shopping-listsYour lists and the ones shared with you, the most recently changed first.
POST
/api/shopping-listsMake a list.
statusisactive,completedorarchived.Body
name*,description,kind,status,space_,id location_id GET
/api/shopping-lists/{id}One list, with everything on it.
PATCH
/api/shopping-lists/{id}Rename, retype, share or archive a list. Only its owner can.
Body
name,description,kind,status,space_id DELETE
/api/shopping-lists/{id}Delete a list.
POST
/api/shopping-lists/{id}/finishFinish a trip: what’s ticked goes into the inventory, and the list changes as its
kindsays.location_records the store you were at.id Body
location_id POST
/api/shopping-lists/{id}/locationsAttach a saved store to a list.
Body
location_*id DELETE
/api/shopping-lists/{id}/locations/{locationId}Detach a store from a list.
What’s on a list
An entry is an item from your inventory (item_) or just a name. A named entry with add_ joins the inventory when it’s ticked and the trip is finished. {entryId} is the entry’s own id, from the list.
POST
/api/shopping-lists/{id}/itemsPut something on a list:
item_orid name, not both.Body
item_orid name*,quantity,unit,add_to_ inventory PATCH
/api/shopping-lists/{id}/items/{entryId}Tick it off (
checked: true) or untick it, change how many, or move it to another aisle.aisle: nullgoes back to the aisle guessed from its name.Body
checked,quantity,name,unit,aisle(at least one)DELETE
/api/shopping-lists/{id}/items/{entryId}Take it off the list.
The aisles are produce, bakery, meat, dairy, frozen, pantry, snacks, drinks, household, personal, babyPet and other.
Stores
radius_ is how close counts as “near” for reminders. aisle_ lists all twelve aisles in the order you walk the store, or is null for the usual order. category is the kind of store, such as grocery_ or pharmacy.
GET
/api/locationsYour saved stores and the ones shared with you.
POST
/api/locationsSave a store. A free account keeps up to three.
Body
name*,address,latitude,longitude,radius_,meters category,space_,id aisle_order PATCH
/api/locations/{id}Change a store. Only its owner can set the aisle order.
DELETE
/api/locations/{id}Delete a store.
Frequently asked questions
Can I use a personal access token with the REST API?
Not yet. The REST endpoints take a signed-in session’s access token. Personal access tokens and OAuth work with the MCP server, which reads and changes the same lists and items.
Does the API need Spisko Plus?
No, apart from what needs Plus in the app too, such as recipes and photos. Personal access tokens and the MCP server do need Plus.
Can the API see other people’s lists?
Only the ones they share with you in a space, as in the app. Every request acts as your account, and the database decides what that account can see.
Want to try it on your own lists?
No credit card required • Works on all devices