Comment

Reading and writing the conversation on a card.

GET /api/data/comment

Parameters

NameTypeRequiredDescription
cardIDintegeryesThe card whose comments you want.
curl -X GET "https://boards.example.com/api/data/comment?cardID=501" \
  -H "X-API-Key: $LOKALBOARDS_KEY"
const response = await fetch("https://boards.example.com/api/data/comment?cardID=501", {
  headers: {
    "X-API-Key": apiKey,
  },
});

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

const data = await response.json();
<script setup>
const config = useRuntimeConfig();

const { data, error } = await useAsyncData("comment", () =>
  $fetch("https://boards.example.com/api/data/comment?cardID=501", {
    headers: { "X-API-Key": config.lokalBoardsKey },
  }),
);
</script>

<template>
  <pre v-if="data">{{ data }}</pre>
  <p v-else-if="error">{{ error.message }}</p>
</template>
import { useEffect, useState } from "react";

export function Example({ apiKey }) {
  const [data, setData] = useState(null);

  useEffect(() => {
    const controller = new AbortController();

    fetch("https://boards.example.com/api/data/comment?cardID=501", {
      headers: { "X-API-Key": apiKey },
      signal: controller.signal,
    })
      .then((response) => response.json())
      .then(setData)
      .catch((error) => {
        if (error.name !== "AbortError") console.error(error);
      });

    return () => controller.abort();
  }, [apiKey]);

  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
<?php

$ch = curl_init('https://boards.example.com/api/data/comment?cardID=501');

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

$response = json_decode(curl_exec($ch), true);
curl_close($ch);

Response

{
  "comments": [
    {
      "id": 88,
      "card": 501,
      "user": "8f3c1e2a-5b7d-4a91-9c8e-2d6f0b4a7e13",
      "authorName": null,
      "content": "Looks promising! Could we try a slightly darker blue?",
      "date": "2026-08-15T19:08:17.000Z"
    }
  ]
}

authorName is set only for comments that came from an import, where the original author has no account here. For everything else the author is user.

POST /api/data/comment

Writes a comment. It appears immediately for everyone with that card open, and notifies the people on the board.

Parameters

NameTypeRequiredDescription
cardintegeryesThe card to comment on.
contentstringyesThe comment.
curl -X POST "https://boards.example.com/api/data/comment" \
  -H "X-API-Key: $LOKALBOARDS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"card": 501, "content": "Ready for review \u2014 the favicon version is in the attachments."}'
const response = await fetch("https://boards.example.com/api/data/comment", {
  method: "POST",
  headers: {
    "X-API-Key": apiKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    card: 501,
    content: "Ready for review \u2014 the favicon version is in the attachments.",
  }),
});

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

const data = await response.json();
<script setup>
const config = useRuntimeConfig();
const pending = ref(false);

async function writeComment() {
  pending.value = true;
  try {
    return await $fetch("https://boards.example.com/api/data/comment", {
      method: "POST",
      headers: { "X-API-Key": config.lokalBoardsKey },
      body: {
        card: 501,
        content: "Ready for review \u2014 the favicon version is in the attachments.",
      },
    });
  } finally {
    pending.value = false;
  }
}
</script>

<template>
  <button :disabled="pending" @click="writeComment()">Post comment</button>
</template>
import { useState } from "react";

export function Example({ apiKey }) {
  const [pending, setPending] = useState(false);

  async function writeComment() {
    setPending(true);

    const response = await fetch("https://boards.example.com/api/data/comment", {
      method: "POST",
      headers: {
        "X-API-Key": apiKey,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        card: 501,
        content: "Ready for review \u2014 the favicon version is in the attachments.",
      }),
    });

    setPending(false);
    return response.json();
  }

  return (
    <button disabled={pending} onClick={writeComment}>
      Post comment
    </button>
  );
}
<?php

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

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
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([
    'card' => 501,
    'content' => "Ready for review — the favicon version is in the attachments.",
]));

$response = json_decode(curl_exec($ch), true);
curl_close($ch);

PUT /api/data/comment

Edits a comment. Only the account that wrote it may change it — an owner's key is no help here, which is what stops a comment being rewritten under somebody else's name.

Parameters

NameTypeRequiredDescription
idintegeryesThe comment's id.
contentstringyesThe new text. It replaces the old one entirely.
curl -X PUT "https://boards.example.com/api/data/comment" \
  -H "X-API-Key: $LOKALBOARDS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"id": 88, "content": "Ready for review."}'
const response = await fetch("https://boards.example.com/api/data/comment", {
  method: "PUT",
  headers: {
    "X-API-Key": apiKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    id: 88,
    content: "Ready for review.",
  }),
});

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

const data = await response.json();
<script setup>
const config = useRuntimeConfig();
const pending = ref(false);

async function editComment() {
  pending.value = true;
  try {
    return await $fetch("https://boards.example.com/api/data/comment", {
      method: "PUT",
      headers: { "X-API-Key": config.lokalBoardsKey },
      body: {
        id: 88,
        content: "Ready for review.",
      },
    });
  } finally {
    pending.value = false;
  }
}
</script>

<template>
  <button :disabled="pending" @click="editComment()">Save comment</button>
</template>
import { useState } from "react";

export function Example({ apiKey }) {
  const [pending, setPending] = useState(false);

  async function editComment() {
    setPending(true);

    const response = await fetch("https://boards.example.com/api/data/comment", {
      method: "PUT",
      headers: {
        "X-API-Key": apiKey,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        id: 88,
        content: "Ready for review.",
      }),
    });

    setPending(false);
    return response.json();
  }

  return (
    <button disabled={pending} onClick={editComment}>
      Save comment
    </button>
  );
}
<?php

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

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
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([
    'id' => 88,
    'content' => "Ready for review.",
]));

$response = json_decode(curl_exec($ch), true);
curl_close($ch);

PATCH /api/data/comment

Ticks a checklist box inside a comment. Anyone who may write on the board may do this, including on somebody else's comment — the same as the interface, where a checklist in a comment is for the team rather than for its author.

Send the comment's whole content with the one - [ ] changed to - [x].

Parameters

NameTypeRequiredDescription
idintegeryesThe comment's id.
contentstringyesThe comment's full text, with the box toggled.
cardIdintegeryesThe card the comment is on.
curl -X PATCH "https://boards.example.com/api/data/comment" \
  -H "X-API-Key: $LOKALBOARDS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 88,
    "cardId": 501,
    "content": "Before we ship:\n\n- [x] Favicon\n- [ ] Social preview"
  }'
const response = await fetch("https://boards.example.com/api/data/comment", {
  method: "PATCH",
  headers: {
    "X-API-Key": apiKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    id: 88,
    cardId: 501,
    content: "Before we ship:\n\n- [x] Favicon\n- [ ] Social preview",
  }),
});

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

const data = await response.json();
<script setup>
const config = useRuntimeConfig();
const pending = ref(false);

async function toggleChecklistItem() {
  pending.value = true;
  try {
    return await $fetch("https://boards.example.com/api/data/comment", {
      method: "PATCH",
      headers: { "X-API-Key": config.lokalBoardsKey },
      body: {
        id: 88,
        cardId: 501,
        content: "Before we ship:\n\n- [x] Favicon\n- [ ] Social preview",
      },
    });
  } finally {
    pending.value = false;
  }
}
</script>

<template>
  <button :disabled="pending" @click="toggleChecklistItem()">Tick off</button>
</template>
import { useState } from "react";

export function Example({ apiKey }) {
  const [pending, setPending] = useState(false);

  async function toggleChecklistItem() {
    setPending(true);

    const response = await fetch("https://boards.example.com/api/data/comment", {
      method: "PATCH",
      headers: {
        "X-API-Key": apiKey,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        id: 88,
        cardId: 501,
        content: "Before we ship:\n\n- [x] Favicon\n- [ ] Social preview",
      }),
    });

    setPending(false);
    return response.json();
  }

  return (
    <button disabled={pending} onClick={toggleChecklistItem}>
      Tick off
    </button>
  );
}
<?php

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

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
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([
    'id' => 88,
    'cardId' => 501,
    'content' => "Before we ship:\n\n- [x] Favicon\n- [ ] Social preview",
]));

$response = json_decode(curl_exec($ch), true);
curl_close($ch);

DELETE /api/data/comment

Deletes a comment. Its author or the board's owner.

Parameters

NameTypeRequiredDescription
commentIdintegeryesThe comment's id.
curl -X DELETE "https://boards.example.com/api/data/comment?commentId=88" \
  -H "X-API-Key: $LOKALBOARDS_KEY"
const response = await fetch("https://boards.example.com/api/data/comment?commentId=88", {
  method: "DELETE",
  headers: {
    "X-API-Key": apiKey,
  },
});

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

const data = await response.json();
<script setup>
const config = useRuntimeConfig();
const pending = ref(false);

async function deleteComment() {
  pending.value = true;
  try {
    return await $fetch("https://boards.example.com/api/data/comment?commentId=88", {
      method: "DELETE",
      headers: { "X-API-Key": config.lokalBoardsKey },
    });
  } finally {
    pending.value = false;
  }
}
</script>

<template>
  <button :disabled="pending" @click="deleteComment()">Delete comment</button>
</template>
import { useState } from "react";

export function Example({ apiKey }) {
  const [pending, setPending] = useState(false);

  async function deleteComment() {
    setPending(true);

    const response = await fetch("https://boards.example.com/api/data/comment?commentId=88", {
      method: "DELETE",
      headers: {
        "X-API-Key": apiKey,
      },
    });

    setPending(false);
    return response.json();
  }

  return (
    <button disabled={pending} onClick={deleteComment}>
      Delete comment
    </button>
  );
}
<?php

$ch = curl_init('https://boards.example.com/api/data/comment?commentId=88');

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

$response = json_decode(curl_exec($ch), true);
curl_close($ch);