Source: https://spooly.eu/en/docs/api/spools

# Spools

Read, create, update, weigh, refill, archive and move spools. Permanent deletion is not possible.

## List spools

`GET /spools`

Sorted by spool number. `fill_level` follows the warning thresholds of the account, as in the app: `low`, `crit` or null. Every field you can write has the same name when you read it. Read only: `id`, `number`, `title` (display name as in the app), `fill_level`, `location` (location as text, as in the app) and `archived`. `material` is the material with its variant as in the app, such as PLA Basic. For multicolor spools `color_hex` holds several colors separated by “; ”.

Parameters:

- `limit` (Query, optional): 1 to 500, default 100
- `offset` (Query, optional): 0 to 1,000,000, default 0
- `archived` (Query, optional): false: active spools (default), true: archived

```bash
curl "https://spooly.eu/api/v1/spools?limit=100" \
  -H "Authorization: Bearer $SPOOLY_KEY"
```

Response (200):

```
{
  "items": [
    {
      "id": "7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21",
      "number": 1,
      "title": "Jade White",
      "name": null,
      "manufacturer": "Bambu Lab",
      "material": "PLA Matte",
      "finish": "matt",
      "color_hex": "#E8E9DF",
      "color_name": "Jade White",
      "remaining_grams": 342,
      "spool_size_grams": 1000,
      "empty_spool_grams": 250,
      "fill_level": "low",
      "location": "Schrank 01 · Fach vorne · Platz 3",
      "location_id": "loc_3c9b7e1a5d60",
      "place": 3,
      "archived": false,
      "price": 19.99,
      "notes": null
    }
  ],
  "total": 23,
  "limit": 100,
  "offset": 0
}
```

## Get one spool

`GET /spools/{spool_id}`

Parameters:

- `spool_id` (Path): The `id` of the spool, not its number

```bash
curl "https://spooly.eu/api/v1/spools/7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21" \
  -H "Authorization: Bearer $SPOOLY_KEY"
```

Response (200):

```
{
  "id": "7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21",
  "number": 1,
  "title": "Jade White",
  "name": null,
  "manufacturer": "Bambu Lab",
  "material": "PLA Matte",
  "finish": "matt",
  "color_hex": "#E8E9DF",
  "color_name": "Jade White",
  "remaining_grams": 342,
  "spool_size_grams": 1000,
  "empty_spool_grams": 250,
  "fill_level": "low",
  "location": "Schrank 01 · Fach vorne · Platz 3",
  "location_id": "loc_3c9b7e1a5d60",
  "place": 3,
  "archived": false,
  "price": 19.99,
  "notes": null
}
```

## Create a spool

`POST /spools`

Responds with 201. Without `remaining_grams` the spool is full.

Parameters:

- `color_hex` (Body): #RRGGBB
- `material` (Body): 1 to 40 characters, the material with its variant as in the app, such as PLA Basic, PLA+ or PETG HF
- `spool_size_grams` (Body): Above 0 up to 20,000 g
- `name` (Body, optional): Up to 80 characters
- `color_name` (Body, optional): Up to 60 characters
- `manufacturer` (Body, optional): Up to 60 characters
- `finish` (Body, optional): `matt`, `shiny`, `satin`, `silk`, `metallic`, `transparent`, `glow_in_dark`, `sparkle`, `marble`, `wood` or `rainbow`
- `remaining_grams` (Body, optional): 0 to 20,000 g, not more than the spool holds
- `empty_spool_grams` (Body, optional): Tare, 0 to 2,000 g
- `price` (Body, optional): 0 to 100,000
- `notes` (Body, optional): Up to 1,000 characters
- `location_id` (Body, optional): Identifier from `GET /locations`
- `place` (Body, optional): Place in the location, 1 to `places`, only with `location_id`
- `Idempotency-Key` (Header, optional): 1 to 128 visible ASCII characters. [Idempotency-Key](https://spooly.eu/en/docs/api#api-idempotenz)

```bash
curl -X POST "https://spooly.eu/api/v1/spools" \
  -H "Authorization: Bearer $SPOOLY_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: neu-petg-0001" \
  -d '{"color_hex":"#1B1B1D","material":"PETG HF","spool_size_grams":1000,"color_name":"Black"}'
```

Response (201):

```
{
  "change_id": 381,
  "spool": {
    "id": "2c9e5a71-0d4b-4e3f-b862-91a7c4d0e5f3",
    "number": 24,
    "title": "Black",
    "name": null,
    "manufacturer": null,
    "material": "PETG HF",
    "finish": null,
    "color_hex": "#1B1B1D",
    "color_name": "Black",
    "remaining_grams": 1000,
    "spool_size_grams": 1000,
    "empty_spool_grams": null,
    "fill_level": null,
    "location": null,
    "location_id": null,
    "place": null,
    "archived": false,
    "price": null,
    "notes": null
  },
  "slot": null,
  "old_grams": null,
  "new_grams": null,
  "replayed": false,
  "task": null,
  "printer": null,
  "stock_empty": null,
  "summary": "Spule #24 Black angelegt"
}
```

## Update a spool

`PATCH /spools/{spool_id}`

Only the fields you send, at least one. Unknown fields return 422. `color_hex`, `material` and `spool_size_grams` cannot be null, you clear the others with null. A `place` of null only removes the place. Weight goes through `/weight` and `/refill`.

Parameters:

- `spool_id` (Path): The `id` of the spool, not its number
- `name, color_hex, color_name, material, manufacturer, finish, spool_size_grams, empty_spool_grams, price, notes, location_id, place` (Body, optional): Same rules as when creating
- `Idempotency-Key` (Header, optional): 1 to 128 visible ASCII characters. [Idempotency-Key](https://spooly.eu/en/docs/api#api-idempotenz)

```bash
curl -X PATCH "https://spooly.eu/api/v1/spools/7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21" \
  -H "Authorization: Bearer $SPOOLY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"notes":"Trocknen vor dem Druck"}'
```

Response (200):

```
{
  "change_id": 381,
  "spool": {
    "id": "7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21",
    "number": 1,
    "title": "Jade White",
    "name": null,
    "manufacturer": "Bambu Lab",
    "material": "PLA Matte",
    "finish": "matt",
    "color_hex": "#E8E9DF",
    "color_name": "Jade White",
    "remaining_grams": 342,
    "spool_size_grams": 1000,
    "empty_spool_grams": 250,
    "fill_level": "low",
    "location": "Schrank 01 · Fach vorne · Platz 3",
    "location_id": "loc_3c9b7e1a5d60",
    "place": 3,
    "archived": false,
    "price": 19.99,
    "notes": null
  },
  "slot": null,
  "old_grams": null,
  "new_grams": null,
  "replayed": false,
  "task": null,
  "printer": null,
  "stock_empty": null,
  "summary": "Spule #1 Jade White bearbeitet"
}
```

## Set remaining weight

`POST /spools/{spool_id}/weight`

Exactly one of the two weights. 0 g archives the spool, as in the app.

Parameters:

- `spool_id` (Path): The `id` of the spool, not its number
- `grams` (Body, optional): 0 to 20,000 g, the filament only
- `gross_grams` (Body, optional): 0 to 40,000 g, spool including tare. The tare must be known.
- `Idempotency-Key` (Header, optional): 1 to 128 visible ASCII characters. [Idempotency-Key](https://spooly.eu/en/docs/api#api-idempotenz)

```bash
curl -X POST "https://spooly.eu/api/v1/spools/7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21/weight" \
  -H "Authorization: Bearer $SPOOLY_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: waage-2026-11-01-0815" \
  -d '{"gross_grams":542}'
```

Response (200):

```
{
  "change_id": 381,
  "spool": {
    "id": "7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21",
    "number": 1,
    "title": "Jade White",
    "name": null,
    "manufacturer": "Bambu Lab",
    "material": "PLA Matte",
    "finish": "matt",
    "color_hex": "#E8E9DF",
    "color_name": "Jade White",
    "remaining_grams": 300,
    "spool_size_grams": 1000,
    "empty_spool_grams": 250,
    "fill_level": "low",
    "location": "Schrank 01 · Fach vorne · Platz 3",
    "location_id": "loc_3c9b7e1a5d60",
    "place": 3,
    "archived": false,
    "price": 19.99,
    "notes": null
  },
  "slot": null,
  "old_grams": 342,
  "new_grams": 300,
  "replayed": false,
  "task": null,
  "printer": null,
  "stock_empty": null,
  "summary": "Spule #1 Jade White: 342 auf 300 g"
}
```

## Refill

`POST /spools/{spool_id}/refill`

Adds grams. The result cannot exceed the spool size.

Parameters:

- `spool_id` (Path): The `id` of the spool, not its number
- `grams` (Body): Above 0 up to 20,000 g
- `Idempotency-Key` (Header, optional): 1 to 128 visible ASCII characters. [Idempotency-Key](https://spooly.eu/en/docs/api#api-idempotenz)

```bash
curl -X POST "https://spooly.eu/api/v1/spools/7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21/refill" \
  -H "Authorization: Bearer $SPOOLY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"grams":250}'
```

Response (200):

```
{
  "change_id": 381,
  "spool": {
    "id": "7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21",
    "number": 1,
    "title": "Jade White",
    "name": null,
    "manufacturer": "Bambu Lab",
    "material": "PLA Matte",
    "finish": "matt",
    "color_hex": "#E8E9DF",
    "color_name": "Jade White",
    "remaining_grams": 592,
    "spool_size_grams": 1000,
    "empty_spool_grams": 250,
    "fill_level": null,
    "location": "Schrank 01 · Fach vorne · Platz 3",
    "location_id": "loc_3c9b7e1a5d60",
    "place": 3,
    "archived": false,
    "price": 19.99,
    "notes": null
  },
  "slot": null,
  "old_grams": 342,
  "new_grams": 592,
  "replayed": false,
  "task": null,
  "printer": null,
  "stock_empty": null,
  "summary": "Spule #1 Jade White: 342 auf 592 g"
}
```

## Archive

`POST /spools/{spool_id}/archive`

The spool leaves the active stock, its print history stays. It does not work during a running print. The API then responds with 409 `spool_in_print`.

Parameters:

- `spool_id` (Path): The `id` of the spool, not its number
- `Idempotency-Key` (Header, optional): 1 to 128 visible ASCII characters. [Idempotency-Key](https://spooly.eu/en/docs/api#api-idempotenz)

```bash
curl -X POST "https://spooly.eu/api/v1/spools/7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21/archive" \
  -H "Authorization: Bearer $SPOOLY_KEY"
```

Response (200):

```
{
  "change_id": 381,
  "spool": {
    "id": "7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21",
    "number": 1,
    "title": "Jade White",
    "name": null,
    "manufacturer": "Bambu Lab",
    "material": "PLA Matte",
    "finish": "matt",
    "color_hex": "#E8E9DF",
    "color_name": "Jade White",
    "remaining_grams": 342,
    "spool_size_grams": 1000,
    "empty_spool_grams": 250,
    "fill_level": "low",
    "location": "Schrank 01 · Fach vorne · Platz 3",
    "location_id": "loc_3c9b7e1a5d60",
    "place": 3,
    "archived": true,
    "price": 19.99,
    "notes": null
  },
  "slot": null,
  "old_grams": null,
  "new_grams": null,
  "replayed": false,
  "task": null,
  "printer": null,
  "stock_empty": null,
  "summary": "Spule #1 Jade White archiviert"
}
```

## Restore

`POST /spools/{spool_id}/restore`

Brings an archived spool back into the active stock.

Parameters:

- `spool_id` (Path): The `id` of the spool, not its number
- `Idempotency-Key` (Header, optional): 1 to 128 visible ASCII characters. [Idempotency-Key](https://spooly.eu/en/docs/api#api-idempotenz)

```bash
curl -X POST "https://spooly.eu/api/v1/spools/7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21/restore" \
  -H "Authorization: Bearer $SPOOLY_KEY"
```

Response (200):

```
{
  "change_id": 381,
  "spool": {
    "id": "7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21",
    "number": 1,
    "title": "Jade White",
    "name": null,
    "manufacturer": "Bambu Lab",
    "material": "PLA Matte",
    "finish": "matt",
    "color_hex": "#E8E9DF",
    "color_name": "Jade White",
    "remaining_grams": 342,
    "spool_size_grams": 1000,
    "empty_spool_grams": 250,
    "fill_level": "low",
    "location": "Schrank 01 · Fach vorne · Platz 3",
    "location_id": "loc_3c9b7e1a5d60",
    "place": 3,
    "archived": false,
    "price": 19.99,
    "notes": null
  },
  "slot": null,
  "old_grams": null,
  "new_grams": null,
  "replayed": false,
  "task": null,
  "printer": null,
  "stock_empty": null,
  "summary": "Spule #1 Jade White zurückgeholt"
}
```

## Move

`POST /spools/{spool_id}/move`

The destination comes from [GET /locations](https://spooly.eu/en/docs/api/locations). A `location_id` of null takes the spool out of its location. With `place` it goes onto that place, without `place` it sits in the location without a place.

Parameters:

- `spool_id` (Path): The `id` of the spool, not its number
- `location_id` (Body): Identifier of the location, or null
- `place` (Body, optional): Place number from 1 to `places` of the location. If the place is taken, you get 409 `place_taken`.
- `Idempotency-Key` (Header, optional): 1 to 128 visible ASCII characters. [Idempotency-Key](https://spooly.eu/en/docs/api#api-idempotenz)

```bash
curl -X POST "https://spooly.eu/api/v1/spools/7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21/move" \
  -H "Authorization: Bearer $SPOOLY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"location_id":"loc_3c9b7e1a5d60","place":3}'
```

Response (200):

```
{
  "change_id": 381,
  "spool": {
    "id": "7f3c2a10-5e1b-4c8e-9a44-2d6b1f0c7e21",
    "number": 1,
    "title": "Jade White",
    "name": null,
    "manufacturer": "Bambu Lab",
    "material": "PLA Matte",
    "finish": "matt",
    "color_hex": "#E8E9DF",
    "color_name": "Jade White",
    "remaining_grams": 342,
    "spool_size_grams": 1000,
    "empty_spool_grams": 250,
    "fill_level": "low",
    "location": "Schrank 01 · Fach vorne · Platz 3",
    "location_id": "loc_3c9b7e1a5d60",
    "place": 3,
    "archived": false,
    "price": 19.99,
    "notes": null
  },
  "slot": null,
  "old_grams": null,
  "new_grams": null,
  "replayed": false,
  "task": null,
  "printer": null,
  "stock_empty": null,
  "summary": "Spule #1 Jade White umgelagert"
}
```
