Data model

Recipes

A user-authored bread recipe in the personal recipe library. Carries identity (name, blurb, difficulty), totals (flour, total, unit/unitPl), an optional hero image, and the two free-form working lists ingredients and phases that drive the guided bake flow.

Model name: bread_recipe
Endpoints: 5
Max page size: 200

Fields

Per-field validation rules. Values that violate any constraint are rejected with 400 before they reach the database.

FieldTypeConstraints
diff
max length32
herostring
max length200
namestring
max length200
unitstring
max length32
blurbstring
max length2000
flourstring
max length64
totalstring
max length64
phaseslist-
unitPlstring
max length32
ingredientslist-

Mutability

Which fields can you send, and when? Anything without a marker is server-managed - sending it isn't an error, it's silently ignored.

Create-only - read from POST body.Patchable - read from PATCH body.Server-managed - ignored on the body.
FieldCreatePatch
diff
hero
name
unit
blurb
flour
total
phases
unitPl
ingredients

Fields marked create-only but not patchable are immutable after creation. Server-managed fields include id, timestamps, ownership, and status.

Filtering & sorting

Combinable on list endpoints. Repeating a filter key produces an IN clause; prefixing a sort key with - reverses direction. Example: ?status=open&status=blocked&sort=-created_at.

Filter keys

namedata__name
diffdata__diff
statusstatus
is_archivedis_archived
owned_byowned_by

Sort keys

created_atcreated_at
updated_atupdated_at
namedata__name

Default: name

Endpoints

Each endpoint below lists its HTTP method, path, and the PAT scope it needs. Code samples cover curl, JavaScript, TypeScript, Python, Rust, Java, and WebSocket.

GET/xapi2/data/bread_recipebread_recipe:list

List objects

Returns a paginated list of objects you can read. Default page size is 20; pass ?limit= to change (capped per type). Use ?after=<id> for keyset pagination on created_at-sorted lists, or ?offset= for offset paging.

curl -H "Authorization: Bearer pat_…" \
"https://sourdoughtracker.com/xapi2/data/bread_recipe?limit=20"
GET/xapi2/data/bread_recipe/{id}bread_recipe:read

Read one

Returns the object by id. 404 if it does not exist or you cannot read it (the two cases are intentionally conflated).

curl -H "Authorization: Bearer pat_…" \
https://sourdoughtracker.com/xapi2/data/bread_recipe/OBJECT_ID
POST/xapi2/data/bread_recipebread_recipe:create

Create

Creates a new object. Body is a flat JSON dict of field values. Server-side fields (id, timestamps, ownership) are filled automatically; only fields listed below as creatable are read from the body.

curl -H "Authorization: Bearer pat_…" \
-H "Content-Type: application/json" \
-X POST https://sourdoughtracker.com/xapi2/data/bread_recipe \
-d '{"name": "…"}'
PATCH/xapi2/data/bread_recipe/{id}bread_recipe:update

Update

Partial update. Only fields included in the body are touched; everything else is preserved. Same allow-list as create, minus the fields that are immutable post-create.

curl -H "Authorization: Bearer pat_…" \
-H "Content-Type: application/json" \
-X PATCH https://sourdoughtracker.com/xapi2/data/bread_recipe/OBJECT_ID \
-d '{"name": "…"}'
DELETE/xapi2/data/bread_recipe/{id}bread_recipe:delete

Delete

Removes the object. It vanishes from every default list immediately and stops being returned by read / list.

curl -H "Authorization: Bearer pat_…" \
-X DELETE https://sourdoughtracker.com/xapi2/data/bread_recipe/OBJECT_ID

Use in CLI

The same endpoints are also exposed via the Sourdough Tracker CLI. For scripts, CI, and bulk imports it's usually the faster path.

sourdoughcli bread_recipe list --limit 5
sourdoughcli bread_recipe get <id>
sourdoughcli bread_recipe create --name "Hello"
sourdoughcli bread_recipe upsert --unique name --csv items.csv
sourdoughcli bread_recipe schema # fields & limits

Full command reference, profiles, CSV import, auto-retry, NDJSON streaming → /docs/cli