bananabay docs

API reference

Current bananabay API routes and the product actions they support.

This reference documents the current route map and what each route is for. It is generated from the shared OpenAPI schema catalog so endpoint response shapes stay in one place.

Use https://api.bananabay.xyz as the origin. Except for GET /api/ping, send Authorization: Bearer $BANANABAY_API_KEY.

Public

GET /api/ping

Checks whether the public API surface can answer a basic request. No API key is required.

Response: 200 OK

Response shape

{
  "msg": "pong"
}

Food inventory

GET /api/food/audit

Reads audit information for food records owned by the authenticated account. Use it when reconciling inventory state.

Response: 200 OK

Response shape

{
  "ok": true,
  "auditType": "product",
  "identifier": "036632032893",
  "facts": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "items": [
    {
      "schemaVersion": 1,
      "id": "food_item_123",
      "name": "Greek yogurt",
      "qty": 2,
      "unit": "container",
      "category": "Dairy",
      "location": "fridge",
      "upc": "036632032893",
      "status": "active",
      "tags": [
        "breakfast"
      ],
      "addedAt": "2026-05-24T15:30:00.000Z",
      "expiresAt": "2026-06-01"
    }
  ],
  "userId": "user_123"
}

GET /api/food/intake

Reads food intake summary data for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "records": [
    {
      "schemaVersion": 1,
      "userId": "user_123",
      "localDate": "2026-05-24",
      "timezone": "America/Denver",
      "entries": [
        {
          "id": "intake_123",
          "itemId": "food_item_123",
          "consumedAt": "2026-05-24T15:30:00.000Z",
          "item": {
            "schemaVersion": 1,
            "id": "food_item_123",
            "name": "Greek yogurt",
            "qty": 2,
            "unit": "container",
            "category": "Dairy",
            "location": "fridge",
            "upc": "036632032893",
            "status": "active",
            "tags": [
              "breakfast"
            ],
            "addedAt": "2026-05-24T15:30:00.000Z",
            "expiresAt": "2026-06-01"
          },
          "macros": {
            "calories": 120,
            "protein": 15
          }
        }
      ],
      "totals": {
        "calories": 120,
        "protein": 15
      },
      "updatedAt": "2026-05-24T15:30:00.000Z"
    }
  ],
  "userId": "user_123"
}

GET /api/food

Lists food inventory records for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "count": 1,
  "total": 1,
  "limit": 50,
  "offset": 0,
  "next_offset": null,
  "items": [
    {
      "schemaVersion": 1,
      "id": "food_item_123",
      "name": "Greek yogurt",
      "qty": 2,
      "unit": "container",
      "category": "Dairy",
      "location": "fridge",
      "upc": "036632032893",
      "status": "active",
      "tags": [
        "breakfast"
      ],
      "addedAt": "2026-05-24T15:30:00.000Z",
      "expiresAt": "2026-06-01"
    }
  ],
  "userId": "user_123"
}

POST /api/food

Creates a food inventory record. Send JSON for the item name, amount, storage details, and any supported inventory fields.

Response: 201 Created

Response shape

{
  "ok": true,
  "id": "food_item_123",
  "userId": "user_123"
}

GET /api/food/items/:itemId

Reads one food inventory item by item ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "item": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "userId": "user_123"
}

PATCH /api/food/items/:itemId

Updates one food inventory item. Send JSON with the fields being changed.

Response: 200 OK

Response shape

{
  "ok": true,
  "item": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "userId": "user_123"
}

DELETE /api/food/items/:itemId

Deletes one food inventory item.

Response: 200 OK

Response shape

{
  "ok": true,
  "id": "food_item_123",
  "userId": "user_123"
}

POST /api/food/items/:itemId/image

Uploads an item-specific food image. Send multipart form data with an image file. The uploaded image is scoped to this inventory item and does not change SKU/product images.

Response: 201 Created

Response shape

{
  "ok": true,
  "image": {
    "id": "food_image_123",
    "url": "/api/food/images/food_image_123",
    "ownerKind": "item",
    "ownerId": "food_item_123",
    "contentType": "image/jpeg",
    "sizeBytes": 38422,
    "fileName": "yogurt.jpg",
    "createdAt": "2026-05-24T15:30:00.000Z"
  },
  "item": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "userId": "user_123"
}

POST /api/food/items/:itemId/adjust

Adjusts an inventory item's amount without replacing the whole record.

Response: 200 OK

Response shape

{
  "ok": true,
  "action": "updated",
  "count": 1,
  "item": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "userId": "user_123"
}

POST /api/food/items/:itemId/consume-grams

Records gram-based consumption for an inventory item.

Response: 200 OK

Response shape

{
  "ok": true,
  "grams": 150,
  "inventoryAction": "updated",
  "item": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "consumedItem": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "remainingItem": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "intakeEntry": {
    "id": "intake_123",
    "itemId": "food_item_123",
    "consumedAt": "2026-05-24T15:30:00.000Z",
    "item": {
      "schemaVersion": 1,
      "id": "food_item_123",
      "name": "Greek yogurt",
      "qty": 2,
      "unit": "container",
      "category": "Dairy",
      "location": "fridge",
      "upc": "036632032893",
      "status": "active",
      "tags": [
        "breakfast"
      ],
      "addedAt": "2026-05-24T15:30:00.000Z",
      "expiresAt": "2026-06-01"
    },
    "macros": {
      "calories": 120,
      "protein": 15
    }
  },
  "userId": "user_123"
}

POST /api/food/items/:itemId/remove

Removes an inventory amount or item using the food removal workflow.

Response: 200 OK

Response shape

{
  "ok": true,
  "removalId": "removal_123",
  "kind": "consume",
  "item": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "undoExpiresAt": "2026-05-24T15:35:00.000Z",
  "userId": "user_123"
}

POST /api/food/removals/:removalId/undo

Undoes a recorded food removal when the removal can still be reversed.

Response: 200 OK

Response shape

{
  "ok": true,
  "removalId": "removal_123",
  "kind": "consume",
  "item": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "userId": "user_123"
}

GET /api/food/search

Searches authenticated food inventory records.

Response: 200 OK

Response shape

{
  "ok": true,
  "searchType": "name",
  "query": "yogurt",
  "status": "matched",
  "items": [
    {
      "schemaVersion": 1,
      "id": "food_item_123",
      "name": "Greek yogurt",
      "qty": 2,
      "unit": "container",
      "category": "Dairy",
      "location": "fridge",
      "upc": "036632032893",
      "status": "active",
      "tags": [
        "breakfast"
      ],
      "addedAt": "2026-05-24T15:30:00.000Z",
      "expiresAt": "2026-06-01"
    }
  ],
  "userId": "user_123"
}

POST /api/food/upc

Looks up or attaches UPC-oriented food information where the product workflow supports it.

Response: 200 OK

Response shape

{
  "ok": true,
  "action": "updated",
  "count": 1,
  "item": {
    "schemaVersion": 1,
    "id": "food_item_123",
    "name": "Greek yogurt",
    "qty": 2,
    "unit": "container",
    "category": "Dairy",
    "location": "fridge",
    "upc": "036632032893",
    "status": "active",
    "tags": [
      "breakfast"
    ],
    "addedAt": "2026-05-24T15:30:00.000Z",
    "expiresAt": "2026-06-01"
  },
  "userId": "user_123"
}

Food labels and facts

GET /api/food/labels

Lists food labels available to the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "labels": [
    {
      "id": "label_123",
      "userId": "user_123",
      "slug": "breakfast",
      "name": "Breakfast",
      "color": "#0ea5e9",
      "scope": "both"
    }
  ],
  "userId": "user_123"
}

POST /api/food/labels

Creates or updates food labels for account-owned food organization.

Response: 200 OK

Response shape

{
  "ok": true,
  "label": {
    "id": "label_123",
    "userId": "user_123",
    "slug": "breakfast",
    "name": "Breakfast",
    "color": "#0ea5e9",
    "scope": "both"
  },
  "userId": "user_123"
}

GET /api/food/facts/resolve

Resolves food facts for an item using available identifiers and account-owned records.

Response: 200 OK

Response shape

{
  "ok": true,
  "record": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "source": "user",
  "resolutionReason": "matched-upc",
  "userId": "user_123"
}

GET /api/food/facts/suggest

Suggests food facts matches that may fit a food item.

Response: 200 OK

Response shape

{
  "ok": true,
  "suggestions": [
    {
      "id": "facts_123",
      "scope": "user",
      "canonicalName": "Greek yogurt",
      "brand": "Example Dairy",
      "category": "Dairy",
      "aliases": [
        "yogurt"
      ],
      "upcs": [
        "036632032893"
      ],
      "sourceLabel": "Personal facts"
    }
  ],
  "userId": "user_123"
}

GET /api/food/facts

Lists personal food facts records for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "entries": [
    {
      "record": {
        "schemaVersion": 1,
        "id": "facts_123",
        "scope": "user",
        "ownerUserId": "user_123",
        "canonicalName": "Greek yogurt",
        "aliases": [
          "yogurt"
        ],
        "upcs": [
          "036632032893"
        ],
        "brand": "Example Dairy",
        "category": "Dairy",
        "source": "manual",
        "nutrition": {
          "perServing": {
            "calories": 120,
            "protein": 15
          }
        },
        "createdAt": "2026-05-24T15:30:00.000Z",
        "updatedAt": "2026-05-24T15:30:00.000Z"
      },
      "linkedInventoryItemCount": 2
    }
  ],
  "count": 1,
  "total": 1,
  "limit": 50,
  "offset": 0,
  "nextOffset": null,
  "userId": "user_123"
}

POST /api/food/facts

Creates a personal food facts record.

Response: 200 OK

Response shape

{
  "ok": true,
  "record": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "userId": "user_123"
}

GET /api/food/facts/:upc

Reads food facts by UPC when a UPC-backed facts record exists.

Response: 200 OK

Response shape

{
  "ok": true,
  "item": {
    "factsId": "facts_123",
    "scope": "user",
    "upc": "036632032893",
    "name": "Greek yogurt",
    "canonicalName": "Greek yogurt",
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual"
  },
  "record": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "source": "user",
  "resolutionReason": "matched-upc",
  "userId": "user_123"
}

PATCH /api/food/facts/:upc

Updates UPC-backed food facts when the authenticated account can edit that record.

Response: 200 OK

Response shape

{
  "ok": true,
  "item": {
    "factsId": "facts_123",
    "scope": "user",
    "upc": "036632032893",
    "name": "Greek yogurt",
    "canonicalName": "Greek yogurt",
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual"
  },
  "record": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "source": "user",
  "resolutionReason": "matched-upc",
  "userId": "user_123"
}

GET /api/food/facts/records/:factsId

Reads a food facts record by facts record ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "record": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "userId": "user_123"
}

PATCH /api/food/facts/records/:factsId

Updates a food facts record by facts record ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "record": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "userId": "user_123"
}

DELETE /api/food/facts/records/:factsId

Deletes a food facts record owned by the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "record": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "userId": "user_123"
}

POST /api/food/facts/records/:factsId/check-upstream

Checks whether a facts record has relevant upstream information available.

Response: 200 OK

Response shape

{
  "ok": true,
  "record": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "changedFields": [
    "nutrition"
  ],
  "diff": [
    {
      "field": "nutrition",
      "label": "Nutrition",
      "status": "changed_upstream",
      "localValue": {
        "calories": 120
      },
      "upstreamValue": {
        "calories": 130
      }
    }
  ],
  "checkedAt": "2026-05-24T15:30:00.000Z",
  "userId": "user_123"
}

POST /api/food/facts/records/:factsId/image

Uploads an image for a personal food facts record. Send multipart form data with an image file. Item-specific image overrides remain separate.

Response: 201 Created

Response shape

{
  "ok": true,
  "image": {
    "id": "food_image_123",
    "url": "/api/food/images/food_image_123",
    "ownerKind": "facts",
    "ownerId": "facts_123",
    "contentType": "image/jpeg",
    "sizeBytes": 38422,
    "fileName": "yogurt.jpg",
    "createdAt": "2026-05-24T15:30:00.000Z"
  },
  "record": {
    "schemaVersion": 1,
    "id": "facts_123",
    "scope": "user",
    "ownerUserId": "user_123",
    "canonicalName": "Greek yogurt",
    "aliases": [
      "yogurt"
    ],
    "upcs": [
      "036632032893"
    ],
    "brand": "Example Dairy",
    "category": "Dairy",
    "source": "manual",
    "nutrition": {
      "perServing": {
        "calories": 120,
        "protein": 15
      }
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  },
  "userId": "user_123"
}

GET /api/food/images/:imageId

Reads an authenticated food image by image ID. Images are only returned to the account that owns the related food item or personal facts record.

Response: 200 OK

Response shape

{
  "contentType": "image/jpeg | image/png | image/webp",
  "body": "<binary image bytes>"
}

Meals

GET /api/meals/plans

Lists meal plans for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "plans": [
    {
      "id": "meal_plan_123",
      "ownerUserId": "user_123",
      "date": "2026-05-24",
      "mealSlot": "breakfast",
      "title": "Yogurt bowl",
      "plannedItems": [
        {
          "inventoryItemId": "food_item_123",
          "quantityNote": "1 container"
        }
      ],
      "createdAt": "2026-05-24T15:30:00.000Z",
      "updatedAt": "2026-05-24T15:30:00.000Z"
    }
  ]
}

POST /api/meals/plans

Creates a meal plan.

Response: 200 OK

Response shape

{
  "ok": true,
  "plan": {
    "id": "meal_plan_123",
    "ownerUserId": "user_123",
    "date": "2026-05-24",
    "mealSlot": "breakfast",
    "title": "Yogurt bowl",
    "plannedItems": [
      {
        "inventoryItemId": "food_item_123",
        "quantityNote": "1 container"
      }
    ],
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  }
}

PATCH /api/meals/plans/:planId

Updates one meal plan by plan ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "plan": {
    "id": "meal_plan_123",
    "ownerUserId": "user_123",
    "date": "2026-05-24",
    "mealSlot": "breakfast",
    "title": "Yogurt bowl",
    "plannedItems": [
      {
        "inventoryItemId": "food_item_123",
        "quantityNote": "1 container"
      }
    ],
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  }
}

DELETE /api/meals/plans/:planId

Deletes one meal plan by plan ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "deletedId": "meal_plan_123"
}

Privacy

GET /api/privacy/user-data

Exports app-owned data for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "userId": "user_123",
  "exportedAt": "2026-05-24T15:30:00.000Z",
  "domains": {
    "siteSettings": {},
    "food": {},
    "schedule": {},
    "meals": {},
    "tasks": {},
    "weather": {}
  },
  "externalProcessors": {
    "clerk": "handled-by-provider",
    "vercel": "handled-by-provider"
  }
}

DELETE /api/privacy/user-data

Deletes app-owned data for the authenticated account. This is destructive and should be called only after explicit user confirmation.

Response: 200 OK

Response shape

{
  "ok": true,
  "userId": "user_123",
  "deletedAt": "2026-05-24T15:30:00.000Z",
  "domains": {
    "siteSettings": {
      "deletedCount": 1
    },
    "food": {
      "deletedCount": 12
    },
    "schedule": {
      "deletedCount": 4
    },
    "meals": {
      "deletedCount": 2
    },
    "tasks": {
      "deletedCount": 6
    },
    "weather": {
      "deletedCount": 3
    }
  },
  "externalProcessors": {
    "clerk": "not-deleted-by-app-operation",
    "vercel": "not-app-owned"
  }
}

Schedule

GET /api/schedule/config

Reads schedule configuration for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "scheduleEngine": "clock",
  "sunWakeAltitudeDegrees": -6,
  "clockWakeTime": "07:30",
  "solarDeathWindowEnabled": true,
  "solarDeathWindowAngleDegrees": 6,
  "latitude": null,
  "longitude": null,
  "timezone": null,
  "locationSource": "user"
}

PATCH /api/schedule/config

Updates schedule configuration.

Response: 200 OK

Response shape

{
  "ok": true,
  "scheduleEngine": "clock",
  "sunWakeAltitudeDegrees": -6,
  "clockWakeTime": "07:30",
  "solarDeathWindowEnabled": true,
  "solarDeathWindowAngleDegrees": 6,
  "latitude": null,
  "longitude": null,
  "timezone": null,
  "locationSource": "user"
}

GET /api/schedule/now

Reads the current schedule state for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "currentBlock": "Breakfast",
  "startIso": "2026-05-24T14:00:00.000Z",
  "endIso": "2026-05-24T14:30:00.000Z",
  "minutesRemaining": 12,
  "weather": null
}

POST /api/schedule/sleep/ingest

Ingests sleep data into the schedule workflow.

Response: 200 OK

Response shape

{
  "ok": true,
  "provider": "health_connect",
  "dataSource": "google_health",
  "count": 1,
  "schedule": {}
}

POST /api/schedule/sleep

Writes sleep information used by the schedule workflow.

Response: 200 OK

Response shape

{
  "ok": true,
  "count": 1
}

GET /api/schedule/today

Reads today's schedule view for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "scheduleEngine": "clock",
  "currentBlock": "Breakfast",
  "blocks": [
    {
      "name": "Breakfast",
      "startIso": "2026-05-24T14:00:00.000Z",
      "endIso": "2026-05-24T14:30:00.000Z"
    }
  ],
  "idealBlocks": [
    {
      "name": "Breakfast",
      "startIso": "2026-05-24T14:00:00.000Z",
      "endIso": "2026-05-24T14:30:00.000Z"
    }
  ],
  "userWakeTime": "07:30",
  "userBedtime": "23:00",
  "locationSource": "user",
  "locationConfigured": true,
  "astroDataAvailable": true,
  "weather": null
}

DELETE /api/schedule/track/comments/:commentId

Deletes one schedule track comment by comment ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "active": {
    "id": "track_123",
    "name": "Deep work",
    "startedAt": "2026-05-24T15:00:00.000Z",
    "stoppedAt": null,
    "comments": []
  }
}

PATCH /api/schedule/track/comments/:commentId

Updates one schedule track comment by comment ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "active": {
    "id": "track_123",
    "name": "Deep work",
    "startedAt": "2026-05-24T15:00:00.000Z",
    "stoppedAt": null,
    "comments": []
  }
}

POST /api/schedule/track/comments

Creates a schedule track comment.

Response: 200 OK

Response shape

{
  "ok": true,
  "active": {
    "id": "track_123",
    "name": "Deep work",
    "startedAt": "2026-05-24T15:00:00.000Z",
    "stoppedAt": null,
    "comments": []
  }
}

DELETE /api/schedule/track

Deletes schedule tracking state for the requested scope.

Response: 200 OK

Response shape

{
  "ok": true,
  "active": null
}

GET /api/schedule/track

Reads schedule tracking state.

Response: 200 OK

Response shape

{
  "ok": true,
  "active": {
    "id": "track_123",
    "name": "Deep work",
    "startedAt": "2026-05-24T15:00:00.000Z",
    "stoppedAt": null,
    "comments": []
  }
}

POST /api/schedule/track

Creates or records schedule tracking state.

Response: 200 OK

Response shape

{
  "ok": true,
  "active": {
    "id": "track_123",
    "name": "Deep work",
    "startedAt": "2026-05-24T15:00:00.000Z",
    "stoppedAt": null,
    "comments": []
  }
}

POST /api/schedule/wake

Records wake information used by the schedule workflow.

Response: 200 OK

Response shape

{
  "ok": true,
  "actualWakeTime": "2026-05-24T13:30:00.000Z",
  "schedule": {}
}

Settings

GET /api/settings/food

Reads food settings for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "food": {
    "consumeLogRetentionDays": 365
  }
}

POST /api/settings/food

Updates food settings.

Response: 200 OK

Response shape

{
  "ok": true,
  "food": {
    "consumeLogRetentionDays": 365
  }
}

GET /api/settings/location

Reads location settings.

Response: 200 OK

Response shape

{
  "ok": true,
  "latitude": 39.7392,
  "longitude": -104.9903,
  "timezone": "America/Denver",
  "location_source": "user"
}

POST /api/settings/location

Updates location settings.

Response: 200 OK

Response shape

{
  "ok": true,
  "latitude": 39.7392,
  "longitude": -104.9903,
  "timezone": "America/Denver",
  "location_source": "user"
}

GET /api/settings/measurement

Reads measurement settings.

Response: 200 OK

Response shape

{
  "ok": true,
  "measurement": {
    "system": "metric",
    "weather": {
      "temperature": "celsius",
      "windSpeed": "kilometers_per_hour",
      "precipitation": "millimeters"
    }
  }
}

POST /api/settings/measurement

Updates measurement settings.

Response: 200 OK

Response shape

{
  "ok": true,
  "measurement": {
    "system": "metric",
    "weather": {
      "temperature": "celsius",
      "windSpeed": "kilometers_per_hour",
      "precipitation": "millimeters"
    }
  }
}

GET /api/settings/tasks

Reads task settings.

Response: 200 OK

Response shape

{
  "ok": true,
  "tasks": {
    "completedTaskRetentionDays": 90,
    "desktopNotificationsEnabled": true
  }
}

POST /api/settings/tasks

Updates task settings.

Response: 200 OK

Response shape

{
  "ok": true,
  "tasks": {
    "completedTaskRetentionDays": 90,
    "desktopNotificationsEnabled": true
  }
}

GET /api/settings/time

Reads time settings.

Response: 200 OK

Response shape

{
  "ok": true,
  "timeFormat": "12h"
}

POST /api/settings/time

Updates time settings.

Response: 200 OK

Response shape

{
  "ok": true,
  "timeFormat": "12h"
}

Tasks

GET /api/tasks

Lists tasks for the authenticated account.

Response: 200 OK

Response shape

{
  "ok": true,
  "tasks": [
    {
      "id": "task_123",
      "ownerUserId": "user_123",
      "title": "Take vitamins",
      "status": "active",
      "subtasks": [],
      "scheduleRule": {
        "type": "recurring-time",
        "frequency": "daily",
        "time": "08:30"
      },
      "createdAt": "2026-05-24T15:30:00.000Z",
      "updatedAt": "2026-05-24T15:30:00.000Z"
    }
  ]
}

POST /api/tasks

Creates a task.

Response: 200 OK

Response shape

{
  "ok": true,
  "task": {
    "id": "task_123",
    "ownerUserId": "user_123",
    "title": "Take vitamins",
    "status": "active",
    "subtasks": [],
    "scheduleRule": {
      "type": "recurring-time",
      "frequency": "daily",
      "time": "08:30"
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  }
}

GET /api/tasks/completions

Lists task completions.

Response: 200 OK

Response shape

{
  "ok": true,
  "completions": [
    {
      "id": "completion_123",
      "taskId": "task_123",
      "completedAt": "2026-05-24T15:30:00.000Z",
      "completedSubtaskIds": [],
      "retained": true,
      "createdAt": "2026-05-24T15:30:00.000Z",
      "updatedAt": "2026-05-24T15:30:00.000Z"
    }
  ]
}

POST /api/tasks/completions

Creates a task completion.

Response: 200 OK

Response shape

{
  "ok": true,
  "completion": {
    "id": "completion_123",
    "taskId": "task_123",
    "completedAt": "2026-05-24T15:30:00.000Z",
    "completedSubtaskIds": [],
    "retained": true,
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  }
}

PATCH /api/tasks/completions/:completionId

Updates one task completion by completion ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "completion": {
    "id": "completion_123",
    "taskId": "task_123",
    "completedAt": "2026-05-24T15:30:00.000Z",
    "completedSubtaskIds": [],
    "retained": true,
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  }
}

DELETE /api/tasks/completions/:completionId

Deletes one task completion by completion ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "deletedId": "completion_123"
}

GET /api/tasks/routines

Lists task routines.

Response: 200 OK

Response shape

{
  "ok": true,
  "routines": [
    {
      "id": "routine_123",
      "ownerUserId": "user_123",
      "title": "Morning routine",
      "status": "active",
      "scheduleRule": {
        "type": "recurring-time",
        "frequency": "daily",
        "time": "08:00"
      },
      "taskIds": [
        "task_123"
      ],
      "createdAt": "2026-05-24T15:30:00.000Z",
      "updatedAt": "2026-05-24T15:30:00.000Z"
    }
  ]
}

POST /api/tasks/routines

Creates a task routine.

Response: 200 OK

Response shape

{
  "ok": true,
  "routine": {
    "id": "routine_123",
    "ownerUserId": "user_123",
    "title": "Morning routine",
    "status": "active",
    "scheduleRule": {
      "type": "recurring-time",
      "frequency": "daily",
      "time": "08:00"
    },
    "taskIds": [
      "task_123"
    ],
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  }
}

PATCH /api/tasks/routines/:routineId

Updates one task routine by routine ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "routine": {
    "id": "routine_123",
    "ownerUserId": "user_123",
    "title": "Morning routine",
    "status": "active",
    "scheduleRule": {
      "type": "recurring-time",
      "frequency": "daily",
      "time": "08:00"
    },
    "taskIds": [
      "task_123"
    ],
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  }
}

DELETE /api/tasks/routines/:routineId

Deletes one task routine by routine ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "deletedId": "routine_123"
}

GET /api/tasks/today

Reads today's task view.

Response: 200 OK

Response shape

{
  "ok": true,
  "date": "2026-05-24",
  "timezone": "America/Denver",
  "entries": [
    {
      "id": "task_123",
      "source": "task",
      "taskId": "task_123",
      "title": "Take vitamins",
      "start": "2026-05-24T14:30:00.000Z",
      "end": null,
      "scheduleRule": {
        "type": "recurring-time",
        "frequency": "daily",
        "time": "08:30"
      },
      "completed": false,
      "overdue": false,
      "completionIds": [],
      "subtaskCount": 0,
      "completedSubtaskCount": 0
    }
  ],
  "pendingConditions": [],
  "appletVariables": []
}

GET /api/tasks/:taskId

Reads one task by task ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "task": {
    "id": "task_123",
    "ownerUserId": "user_123",
    "title": "Take vitamins",
    "status": "active",
    "subtasks": [],
    "scheduleRule": {
      "type": "recurring-time",
      "frequency": "daily",
      "time": "08:30"
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  }
}

PATCH /api/tasks/:taskId

Updates one task by task ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "task": {
    "id": "task_123",
    "ownerUserId": "user_123",
    "title": "Take vitamins",
    "status": "active",
    "subtasks": [],
    "scheduleRule": {
      "type": "recurring-time",
      "frequency": "daily",
      "time": "08:30"
    },
    "createdAt": "2026-05-24T15:30:00.000Z",
    "updatedAt": "2026-05-24T15:30:00.000Z"
  }
}

DELETE /api/tasks/:taskId

Deletes one task by task ID.

Response: 200 OK

Response shape

{
  "ok": true,
  "deletedId": "task_123"
}

Weather

POST /api/weather/report

Creates or refreshes the weather report used by the authenticated account's settings and schedule workflows.

Response: 200 OK

Response shape

{
  "ok": true,
  "report": {
    "provider": "openweathermap",
    "location": {
      "latitude": 39.7392,
      "longitude": -104.9903
    },
    "units": "metric",
    "timezone": "America/Denver",
    "timezoneOffsetSeconds": -21600,
    "current": {
      "observedAt": 1779636600,
      "temperature": 18.4,
      "feelsLike": 18.1,
      "pressure": 1014,
      "humidity": 35,
      "dewPoint": 2.4,
      "uvIndex": 4.2,
      "cloudCover": 20,
      "visibility": 10000,
      "windSpeed": 3.4,
      "windDirection": 220,
      "conditions": [
        {
          "id": 801,
          "main": "Clouds",
          "description": "few clouds",
          "icon": "02d"
        }
      ]
    },
    "hourly": [],
    "daily": []
  },
  "capturedAt": "2026-05-24T15:30:00.000Z",
  "appletVariables": []
}

On this page

PublicGET /api/pingResponse shapeFood inventoryGET /api/food/auditResponse shapeGET /api/food/intakeResponse shapeGET /api/foodResponse shapePOST /api/foodResponse shapeGET /api/food/items/:itemIdResponse shapePATCH /api/food/items/:itemIdResponse shapeDELETE /api/food/items/:itemIdResponse shapePOST /api/food/items/:itemId/imageResponse shapePOST /api/food/items/:itemId/adjustResponse shapePOST /api/food/items/:itemId/consume-gramsResponse shapePOST /api/food/items/:itemId/removeResponse shapePOST /api/food/removals/:removalId/undoResponse shapeGET /api/food/searchResponse shapePOST /api/food/upcResponse shapeFood labels and factsGET /api/food/labelsResponse shapePOST /api/food/labelsResponse shapeGET /api/food/facts/resolveResponse shapeGET /api/food/facts/suggestResponse shapeGET /api/food/factsResponse shapePOST /api/food/factsResponse shapeGET /api/food/facts/:upcResponse shapePATCH /api/food/facts/:upcResponse shapeGET /api/food/facts/records/:factsIdResponse shapePATCH /api/food/facts/records/:factsIdResponse shapeDELETE /api/food/facts/records/:factsIdResponse shapePOST /api/food/facts/records/:factsId/check-upstreamResponse shapePOST /api/food/facts/records/:factsId/imageResponse shapeGET /api/food/images/:imageIdResponse shapeMealsGET /api/meals/plansResponse shapePOST /api/meals/plansResponse shapePATCH /api/meals/plans/:planIdResponse shapeDELETE /api/meals/plans/:planIdResponse shapePrivacyGET /api/privacy/user-dataResponse shapeDELETE /api/privacy/user-dataResponse shapeScheduleGET /api/schedule/configResponse shapePATCH /api/schedule/configResponse shapeGET /api/schedule/nowResponse shapePOST /api/schedule/sleep/ingestResponse shapePOST /api/schedule/sleepResponse shapeGET /api/schedule/todayResponse shapeDELETE /api/schedule/track/comments/:commentIdResponse shapePATCH /api/schedule/track/comments/:commentIdResponse shapePOST /api/schedule/track/commentsResponse shapeDELETE /api/schedule/trackResponse shapeGET /api/schedule/trackResponse shapePOST /api/schedule/trackResponse shapePOST /api/schedule/wakeResponse shapeSettingsGET /api/settings/foodResponse shapePOST /api/settings/foodResponse shapeGET /api/settings/locationResponse shapePOST /api/settings/locationResponse shapeGET /api/settings/measurementResponse shapePOST /api/settings/measurementResponse shapeGET /api/settings/tasksResponse shapePOST /api/settings/tasksResponse shapeGET /api/settings/timeResponse shapePOST /api/settings/timeResponse shapeTasksGET /api/tasksResponse shapePOST /api/tasksResponse shapeGET /api/tasks/completionsResponse shapePOST /api/tasks/completionsResponse shapePATCH /api/tasks/completions/:completionIdResponse shapeDELETE /api/tasks/completions/:completionIdResponse shapeGET /api/tasks/routinesResponse shapePOST /api/tasks/routinesResponse shapePATCH /api/tasks/routines/:routineIdResponse shapeDELETE /api/tasks/routines/:routineIdResponse shapeGET /api/tasks/todayResponse shapeGET /api/tasks/:taskIdResponse shapePATCH /api/tasks/:taskIdResponse shapeDELETE /api/tasks/:taskIdResponse shapeWeatherPOST /api/weather/reportResponse shape