Beaver API
Beaver is Almond's production system: parts, BOMs, inventory, purchase orders, builds, and assembly instructions. Everything in the UI is available over a JSON REST API so any coding agent or script can read and write the same data.
- Base URL:
https://beaver.almond.bot/api/v1 - Auth: every request needs
Authorization: Bearer bvr_...(ask a teammate for the key, or mint a new one in theapi_keystable — store the sha256 hex of the key inkey_hash). - Machine-readable index:
GET /api/v1lists every endpoint. - IDs: part endpoints accept either the numeric id or the IPN (e.g.
ALM-000001).
Quick start (Python)
import requests
BASE = "https://beaver.almond.bot/api/v1"
H = {"Authorization": "Bearer bvr_..."}
# find a part
parts = requests.get(f"{BASE}/parts", params={"q": "wrist"}, headers=H).json()["parts"]
# how many Axols can we build, and what's short for 10?
bom = requests.get(f"{BASE}/parts/ALM-000001/bom", params={"quantity": 10}, headers=H).json()
print(bom["buildable"], [r for r in bom["availability"] if r["short"] > 0])
# receive 50 screws (inventory +50)
requests.post(f"{BASE}/parts/ALM-000042/inventory", json={"delta": 50, "reason": "restock"}, headers=H)
# set an absolute count after a shelf audit
requests.post(f"{BASE}/parts/ALM-000042/inventory", json={"quantity": 137}, headers=H)
# build 2 wrist assemblies: consumes the BOM, adds 2 finished units
b = requests.post(f"{BASE}/builds", json={"part_id": 928, "quantity": 2}, headers=H).json()["build"]
requests.post(f"{BASE}/builds/{b['id']}/complete", headers=H)
Core concepts
Parts
Every physical item — products, subassemblies, fasteners, consumables. Each part has an
IPN (ALM-######), a category, a picture, and live on_hand / on_order counts.
on_hand is never written directly: it is the sum of inventory events.
BOMs
bom_items link a parent assembly to child parts with a quantity.
GET /parts/:id/bom returns direct children, the fully exploded flat BOM,
per-child availability for a target quantity, and buildable (how many the
current stock supports).
Inventory
Append-only inventory_events move stock. Three ways stock changes:
- Manual / count —
POST /parts/:id/inventorywithdelta(relative) orquantity(absolute). - Receiving an order —
POST /orders/:id/receiveadds the order quantity. - Completing a build —
POST /builds/:id/completesubtracts the BOM children and adds the finished assemblies.
Orders (shopping list)
An order is a line for one part: requested → ordered → shipped → received (or cancelled).
Open orders count toward the part's on_order. The Orders page is the shopping list;
GET /orders?status=requested is "still to buy".
Builds
POST /builds {part_id, quantity} starts a build of an assembly.
GET /builds/:id shows required parts and shortages before you commit.
POST /builds/:id/complete performs the inventory moves in one transaction.
Assembly instructions (processes)
A process has ordered steps; each step has markdown and picture URLs.
GET /processes/:id returns steps with resolved image_urls.
Add pictures with POST /processes/:id/steps/:stepId/image (multipart, field image).
Video → instructions pipeline
POST /video-jobs/upload-url {filename}→ returnspath+upload_urlPUTthe raw video bytes toupload_url(Content-Type: video/mp4)POST /video-jobs {video_path: path, part_id?, hints?}POST /video-jobs/:id/process— blocks for a few minutes while frames are extracted and a vision model writes the steps. Returnsprocess_id.- Review the draft at
https://beaver.almond.bot/instructions/{process_id}and publish.
If step 4 fails with a rate-limit error (the AI Gateway free tier is tightly rate-limited), wait a few minutes and re-run it — the job is safely retryable.
Conventions (ported from Anvil)
- IPN prefix is ALM- with a six-digit sequence; new parts auto-assign the next one if you omit
ipn. - Categories: Product, Subassembly, Electronics, Fasteners, Wiring, Structure, Mechanical, Consumable, Tooling, Material. Match existing spellings.
manufactureris the actual maker; distributors (McMaster-Carr, Amazon, DigiKey…) belong in supplier links with URL/SKU/price.procurement_type:OTS(off the shelf),MTS(made to spec),Make(built here).- Fastener naming:
BH-TX-M3-08(head-drive-size-length), no leading zeros in descriptions.
Direct database access
The data lives in Supabase Postgres (project jukbsqdjwfmjhycdvjkw). Agents with Supabase
access can query it directly; the REST API above is preferred for writes because it goes
through the same domain functions (adjust_inventory, complete_build, receive_order,
set_inventory_count) that keep counts consistent.