Labels

The words a board is using.

A label is text on a card, not an entry in a list the board keeps. You put a word on the card it applies to, and the row here exists so that the same word typed on two cards is one thing rather than two — which is what lets a board be filtered by it, and what fills the handful of names offered the next time somebody adds one.

That shape is why this page is short. There is no renaming and no deleting here: which labels a card wears travels with the card, as labelIds on PUT /api/data/card, and a word no card wears any longer is removed on the same request that drops it. Use this endpoint to find out what a board is already using, and to turn a word into the id the card endpoint wants.

Every label is drawn in the same colour, so there is nothing to set.

GET /api/data/labels

The words in use on a board, in the order they were first used. Needs read access to the board.

Parameters

NameTypeRequiredDescription
boardIdintegeryesThe board to read.

What comes back

FieldTypeDescription
labelsarrayEach entry an id and a name.
curl -X GET "https://boards.example.com/api/data/labels?boardId=123" \
  -H "X-API-Key: $LOKALBOARDS_KEY"
const response = await fetch(
  "https://boards.example.com/api/data/labels?boardId=123",
  { headers: { "X-API-Key": apiKey } },
);

if (!response.ok) throw new Error(await response.text());

const { labels } = await response.json();
<script setup>
const config = useRuntimeConfig();

const { data } = await useAsyncData("labels", () =>
  $fetch("https://boards.example.com/api/data/labels", {
    headers: { "X-API-Key": config.lokalBoardsKey },
    query: { boardId: 123 },
  }),
);

const labels = computed(() => data.value?.labels ?? []);
</script>

<template>
  <ul>
    <li v-for="label in labels" :key="label.id">{{ label.name }}</li>
  </ul>
</template>
import { useEffect, useState } from "react";

export function Example({ apiKey }) {
  const [labels, setLabels] = useState([]);

  useEffect(() => {
    fetch("https://boards.example.com/api/data/labels?boardId=123", {
      headers: { "X-API-Key": apiKey },
    })
      .then((response) => response.json())
      .then((data) => setLabels(data.labels));
  }, [apiKey]);

  return (
    <ul>
      {labels.map((label) => (
        <li key={label.id}>{label.name}</li>
      ))}
    </ul>
  );
}
<?php

$ch = curl_init('https://boards.example.com/api/data/labels?boardId=123');

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: ' . $apiKey,
]);

$labels = json_decode(curl_exec($ch), true)['labels'];
curl_close($ch);

POST /api/data/labels

A word, in exchange for the label that is that word on this board. If the board is already using it you get the one it has; if not, one is made. Which of the two happened is not something you need to know — either way the answer is the id to put in a card's labelIds. Needs edit access.

Names are compared the way the database compares them, without regard to case, so Bug and bug are the same label rather than two.

A board is capped at 30 labels in use. Asking for a thirty-first new word answers 400 with TOO_MANY_LABELS; asking for a word already in use always works, since it adds nothing.

Parameters

NameTypeRequiredDescription
boardIdintegeryesThe board the word belongs to.
namestringyesThe word. Trimmed, and at most 64 characters.

What comes back

FieldTypeDescription
labelobjectThe id and name to use.
# The word, then the card: two requests, because the second one needs the id.
curl -X POST "https://boards.example.com/api/data/labels" \
  -H "X-API-Key: $LOKALBOARDS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "boardId": 123, "name": "Bug" }'

curl -X PUT "https://boards.example.com/api/data/card" \
  -H "X-API-Key: $LOKALBOARDS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "cardID": 501, "name": "Ports lassen sich nicht freigeben", "labelIds": [7] }'
// A word on a card, whether or not the board has used it before.
async function label(cardId, cardName, word) {
  const { label } = await fetch("https://boards.example.com/api/data/labels", {
    method: "POST",
    headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
    body: JSON.stringify({ boardId: 123, name: word }),
  }).then((r) => r.json());

  // `labelIds` replaces the card's labels, so send the whole set.
  return fetch("https://boards.example.com/api/data/card", {
    method: "PUT",
    headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
    body: JSON.stringify({ cardID: cardId, name: cardName, labelIds: [label.id] }),
  });
}
<script setup>
const config = useRuntimeConfig();

async function addLabel(word) {
  const { label } = await $fetch("https://boards.example.com/api/data/labels", {
    method: "POST",
    headers: { "X-API-Key": config.lokalBoardsKey },
    body: { boardId: 123, name: word },
  });
  return label.id;
}
</script>
async function addLabel(apiKey, word) {
  const response = await fetch("https://boards.example.com/api/data/labels", {
    method: "POST",
    headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
    body: JSON.stringify({ boardId: 123, name: word }),
  });

  if (!response.ok) throw new Error(await response.text());

  const { label } = await response.json();
  return label.id;
}
<?php

$ch = curl_init('https://boards.example.com/api/data/labels');

curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: ' . $apiKey,
    'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'boardId' => 123,
    'name' => 'Bug',
]));

$label = json_decode(curl_exec($ch), true)['label'];
curl_close($ch);

Taking a label off a card

There is no endpoint for it here. Send the card the set it should have, without that one:

curl -X PUT "https://boards.example.com/api/data/card" \
  -H "X-API-Key: $LOKALBOARDS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "cardID": 501, "name": "Ports lassen sich nicht freigeben", "labelIds": [] }'

If that was the last card using the word, the word goes with it and stops being offered. Typing it again makes it again.