LibraryCraft

Item format and feed

How a library item is stored, and the API and open feed that apps and other libraries use to read it.

The item file

Every version of every item is one JSON document, item.json, media type application/json. It is called "CadCraft library item", format 1. A published version never changes; a changed item is a new version with a higher number.

  • Every length is in millimeters and every angle in degrees.
  • Z is up. The plan lies in X and Y at z = 0, and the insertion point is (0, 0, 0).
  • The item's front faces −Y and its back is the +Y side: "back against a wall" means the plan's largest Y touches the wall.
{
  "format": "cadcraft-library-item",
  "format_version": 1,
  "uuid": "…",
  "version": 3,
  "name": "Three-compartment sink, 90 in",
  "kind": "equipment",
  "category": "foodservice/sinks",
  "description": "…",
  "maker": "", "model": "",
  "ifc": { "class": "IfcFurnishingElement", "predefined": "NOTDEFINED" },
  "plan": {
    "layers": [{ "name": "EQUIP", "color": 7 }],
    "entities": [{ "type": "line", "layer": "EQUIP", "color": null, "x1": 0, "y1": 0, "x2": 100, "y2": 0 }]
  },
  "body": { "type": "box", "x": -1143, "y": -762, "z": 0, "w": 2286, "d": 762, "h": 1092 },
  "clearances": [{ "name": "service", "x": 0, "y": -900, "z": 0, "w": 2286, "d": 900, "h": 2000 }],
  "params": {
    "width": 2286, "depth": 762, "height": 1092, "weight_kg": 0,
    "elec": { "volts": "", "phase": "", "amps": "", "kw": "", "hp": "", "hz": "", "plug": "", "nema": "", "direct": "" },
    "plumb": { "cw": "", "hw": "", "dd": "", "id": "", "gas": "" },
    "remarks": ""
  },
  "source_attrs": { "ATTRIBUTE-TAG": "value as found in the file" },
  "license": { "id": "CC-BY-4.0", "holder": "…", "attribution": "…", "url": "https://creativecommons.org/licenses/by/4.0/" },
  "provenance": { "library": "librarycraft", "item": "…", "version": 3, "sha256": "…",
                  "source_file": "name.dwg", "source_sha256": "…", "published_at": "2026-10-10T00:00:00Z" }
}

Fields

FieldWhat it holds
format, format_versionAlways "cadcraft-library-item" and 1.
uuid, versionThe item (stable across versions) and its version number, starting at 1. Filled by the library.
name, descriptionPlain text.
kindequipment, furniture, fixture, symbol, detail.
categoryA taxonomy key such as foodservice/sinks. The full list is in the browse filter; there are 36 keys in 12 groups.
maker, modelEmpty for generic items. Never invented.
ifcThe IFC class an app uses when it places the item in a model, with its predefined type.
planThe 2D symbol: layers (name, color) and entities (below).
bodyThe 3D body: a box (x, y, z, w, d, h), a mesh (positions as x, y, z triples and indices as triangles), or null for a 2D symbol.
clearancesOptional named boxes (service space, door swing) in the same coordinates.
paramsWidth, depth, height (mm) and weight (kg) as numbers; electrical (volts, phase, amps, kW, HP, Hz, plug, NEMA, direct) and plumbing (cold and hot water, direct and indirect drain, gas) as text; remarks. All optional.
source_attrsAttributes exactly as found in the source file, as text, never edited. Item numbers and quantities are not part of an item: they belong to each placement.
licenseThe license id (one of CC0-1.0, CC-BY-4.0, CC-BY-3.0, CC-BY-SA-4.0, MAKER-TERMS, TEAM-ONLY), the holder, the credit line and the license link.
provenanceWhere the file came from: the library, item and version, the sha256 of the item without its provenance, the source file's name and sha256, and when it was published. Filled by the library.

Plan entities

Plan entities use the CadCraft drawing shapes. Each carries layer and color: null means by layer, 0 by block, 1 to 255 an indexed color, or "#rrggbb". Nested blocks are exploded when an item is made.

TypeFields
linex1, y1, x2, y2
circlex, y, r
arcx, y, r, a0, a1 (degrees, counterclockwise)
polypts: [[x, y, bulge?], …], closed
ellipsethe CadCraft ellipse shape
textx, y, h, rot, value
pointx, y
hatchboundary loops only, drawn solid

Linetypes by layer name

Format 1 has no linetype field. The library and the apps draw each entity by its layer's name, so a plan symbol reads like a drawn plan without a format change. The first rule that matches wins; matching ignores case.

Layer name containsDrawn asUse it for
clear, swing or serviceLight dotted lineDoor swings, service space, access clearances
hidden, dashed, above or belowDashed lineParts under a top (undershelves, legs), doors shown open below, items above the cut such as wall shelves
center or centreCentre lineCentre lines
detail, thin or fineThin lineRibs, grates, knobs, drains and other small detail
anything elseObject lineEverything else

The closed shape whose extent matches the body's footprint (or the plan's extent when there is no box body) is drawn as the heavy outline and lightly filled. Text in a plan is shown only on the item page, never on cards: an item tag belongs to each placement, not to the symbol. The generic items use the layers EQUIP, EQUIP-DETAIL, EQUIP-HIDDEN, EQUIP-CENTER and EQUIP-SWING.

Uploading a finished item

Besides drawings and models, Upload takes a finished item: a .json file in format 1, as a maker's own tools can write it. It is checked with the same validation, without the fields the library fills in. uuid, version, license and provenance are left out if present, and you choose the license and declare the source on the form as with any upload. The file becomes one candidate, and its drawing is made from the item itself.

Validation

The library checks every version with the same rules the apps use:

  • the required fields are present with the right types, and format_version is 1;
  • the category is in the taxonomy and the license is one of the allowed ids;
  • numbers are finite and within ±10,000,000 mm;
  • the JSON is at most 8 MB; a mesh has at most 200,000 triangles and every index is in range;
  • text values are at most 500 characters and a plan has at most 50,000 entities;
  • no keys outside the format, except under source_attrs.

Uploaded source files can be up to 50 MB, with at most 500 blocks per upload.

Library API

The public parts answer without a key and send Access-Control-Allow-Origin: *. Every response is JSON in the envelope {"status": "success", "data": …}, or "status": "error" with a message. Team items appear only to a signed-in app whose user is a member of that team (Authorization: Bearer …).

List and search

GET https://getcadcraft.com/api/v1/library/items?q=&category=&kind=&license=&maker=&page=&per=
→ data: { items: [{ uuid, slug, name, kind, category, maker, model, license, version,
                    preview_url, item_url, updated_at, visibility }], page, per, total }

One item and its versions

GET https://getcadcraft.com/api/v1/library/items/{uuid}
→ data: { item: { …the list fields, description, author: { uuid, name },
                  versions: [{ version, status, change_kind, changelog, license, published_at,
                               item_url, preview_url, source_url|null, withdrawn_reason|null }] } }

GET https://getcadcraft.com/api/v1/library/items/{uuid}/{version}/item.json
→ 302 to the file; 451 when the version was withdrawn for copyright

Check for updates

POST https://getcadcraft.com/api/v1/library/updates
{ "items": [{ "uuid": "…", "version": 2 }] }          (at most 500)
→ data: { results: [{ uuid, version, latest|null, status: "current" | "newer" | "withdrawn" | "unknown",
                      change_kinds: [], license_changed, withdrawn_reason|null }] }

Change kinds are geometry, data, license, fix. A copy someone already placed keeps the license it was placed under.

Signed-in apps

POST   /api/v1/library/uses            { uuid, version, app, file_label? }
DELETE /api/v1/library/uses?id=
GET    /api/v1/library/notifications?unread=1
POST   /api/v1/library/notifications/read   { ids: [] }  or  { all: true }
POST   /api/v1/library/follows          { target_type: item|author|maker|category, target_key }
DELETE /api/v1/library/follows?id=

An app gets its key when you sign it in to the library from inside the app; you can revoke it on your account's security page.

Open feed

The feed is the open part: any library can serve it, and the apps can read any library that does ("Other feeds" in their library panel).

GET https://getcadcraft.com/api/v1/library/feed?since=<ISO 8601>&limit=
→ data: { events: [{ at, type: "item_published" | "version_published" | "version_withdrawn" | "license_changed",
                     uuid, version, item_url }], next_since }

Events are public items only, oldest first. Pass next_since back as since to continue; since is exclusive and a page never splits one second's events, so nothing is skipped.

To be an "other feed", serve /items, /items/{uuid}, /updates and /feed under one https base address with the shapes above, and allow cross-origin requests.