Hopp til hovedinnholdet

TypeScript SDK

@kanera/sdk er en typet klient for Kanera offentlig API. Den har ingen runtime avhengigheter og er bygget på global fetch, så det kjører uendret på Node 18+, Bun, Deno, Cloudflare Workers og nettlesere.

npm install @kanera/sdk
import { Kanera } from "@kanera/sdk";

const kanera = new Kanera({ apiKey: process.env.KANERA_API_KEY! });

const session = await kanera.session();
if (session.scope === "read") throw new Error("this credential cannot write");

for await (const card of kanera.work.iterateCards()) {
console.log(card.key, card.title);
}

await kanera.cards.setCompletion("MKT-42", true);
await kanera.comments.create("MKT-42", { body: "Shipped in 1.4.0." });

SDK er publisert under MIT lisens, bevisst mer ettergivende enn Kanera-serveren (Elastic License 2.0), så å legge den inn i ditt eget program gir ingen lisenspolitiske spørsmål.

Autentiser​

Opprette en API-nøkkel i Profilinnstillinger -> API-nøkler eller Arbeidsområdeinnstillinger -> API, og lese det fra miljøet i stedet for å forplikte seg til det. Se Velg en API-nøkkeltype hvilken type som passer din integrasjon.

const kanera = new Kanera({ apiKey: process.env.KANERA_API_KEY! });

Selvhosting? Pek klienten på din egen distribusjon:

const kanera = new Kanera({ apiKey, baseUrl: "https://api.your-kanera.example" });

Sjekk omfanget først​

const { scope } = await kanera.session();

read Hver eneste mutasjon vil bli avvist med en FORBIDDEN Det er billigere å sjekke en gang ved oppstart enn å oppdage det halvveis gjennom en migrering.

Hva er på klienten​

NavneromOmslag
kanera.workspacesArbeidsområder, deres tavler, medlemmer og automatiseringer
kanera.boardsTilgjengelige tavle, åpne en tavle, brettkort og aktivitet; watch og unwatch
kanera.listsKortoperasjoner på listenivå: arkiv, flytt, sett ferdigstillelse
kanera.separatorsOpprette, utforme, plassere, flytte og slette skilletegn for brettlister
kanera.cardsKort, pluss .attachments, .checklists, og .bulkSe og gjør oppmerksom påwatch, unwatch, setReminder, clearReminder, listReminders, followState); pollNotifications
kanera.commentsKort kommentarer og reaksjoner
kanera.runsAgent kjører: kunngjør, hjerteslag og fullfør in-flight arbeid på et kort
kanera.notesNotater, tilbakekoblinger og notatvedlegg
kanera.searchSøk på tvers av tilgjengelig innhold
kanera.workArbeid over tavle, historikk, tidsplaner, samlesammendrag og neste køer
kanera.automationsArbeidsområdeautomatiseringsregler og skrevet kjørehistorikk
kanera.webhookEndpointsRegistrer og administrer utgående webhooks, inspiserer leveranser og prøver feil på nytt
kanera.httpRå forespørsel klient, for noe ennå ikke pakket

Kortreferanser​

Hvor som helst et kort er navngitt, passerer en UUID, en menneskelig nøkkel som MKT-42, eller en kanonisk kort URL. Nøkler løses en gang per klient og bufret, så gjenta en over en bulk operasjon koster en enkelt oppslag.

Et nøkkelprefiks er unikt bare i en organisasjon, og en personlig legitimasjon kan se flere. En nøkkel synlig i mer enn en er avvist, uten å gjette — oppgi den kanoniske URL-en eller UUID-en for å unngå tvetydighet.

Tidslinjeplaner​

Les samme arbeidsdagsplan som Tidslinjevisning:

const schedule = await kanera.work.schedule({ boardId }); // or { workspaceId }, never both
console.log(schedule.summary.projectedFinish, schedule.summary.slipDays);
const critical = schedule.cards.filter(card => card.critical);
const conflicts = schedule.cards.filter(card => card.conflicts.length > 0);

// This changes the card's saved dates; it requires write access.
await kanera.cards.update("MKT-42", {
startDateLocalDate: "2026-11-02",
dueDateLocalDate: "2026-11-06",
});
const after = await kanera.work.schedule({ boardId });

Varighet, slackDays, konflikt days, og summary.slipDays teller mandag-fredag arbeidsdager. plannedStart / plannedEnd beskrive planen; tidligste/siste datoer beskrive avhengighet beregning. Schedule følger tilgjengelige tilkoblede kjeder på tvers av tavle og utelater fullførte og utilgjengelige kort. Det gjelder ikke automatisk datoer til etterfølgere.

For en personlig orientering, kanera.work.scheduleAttention({ limit: 10 }) returnerer tildelte seksjoner for konflikt, kritiske seksjoner og seksjoner for sen oppstart. kanera.work.portfolio() returnerer den støttede rulleoppstillingen på tvers av tavlen med helse for hver brettplan. MCP-hendelser er en separat vertsprotokoll fra SDK- Vanlige webhook-hjelpere.

Kortforhold​

Lese, legge til og fjerne avhengigheter med de maskinskrevne kortmetodene. Referanser kan være nøkler, UUID-er eller kanoniske kortadresser.

// MKT-42 blocks WEB-18. Both cards must belong to the same workspace.
const relation = await kanera.cards.addRelation("MKT-42", "WEB-18", "blocks");
await kanera.cards.addRelation("WEB-18", "MKT-43", "blocked_by");
await kanera.cards.addRelation("WEB-18", "MKT-44", "relates_to");

const { relations, hiddenBlockerCount } = await kanera.cards.listRelations("WEB-18");
const detail = await kanera.cards.get("WEB-18"); // also includes relations
const waiting = await kanera.work.cards({ filters: { blockedOnly: true } });
await kanera.cards.removeRelation("MKT-42", relation.id);

listRelations bare kort legitimasjonen kan åpne. Skjulte aktive blokkeringer bidra til å hiddenBlockerCount. Legger er idempotent; sykluser og fullførte kort som nye blokkerer blir avvist. Arbeidsspørringsfiltrene støtter også blockedOnly: true for å finne blokkerte åpne kort på tilgjengelige tavle, og atRiskOnly: true for åpne kort som har en synlig blokkering som er forsinket eller forfalt etter dem. Å fullføre et kort gjennom SDK viser ikke webappens blokkerte arbeid advarsel.

Avhengighetsgrafer​

cards.dependencyGraph leser den samme avgrensede grafen som nettvisningen. Velg ett tavle, arbeidsområde eller sett med kortreferanser:

const aroundCard = await kanera.cards.dependencyGraph({ cards: ["MKT-42"] });
const boardGraph = await kanera.cards.dependencyGraph({ boardId });
const workspaceGraph = await kanera.cards.dependencyGraph({ workspaceId });

for (const edge of aroundCard.edges) {
console.log(edge.sourceCardId, edge.kind, edge.targetCardId);
}

Resultatet inkluderer kort, kanter, oppslag, kort-face tilpassede felt, tavle canEdit Flagg og truncated. cards godtar nøkler, UUID-er eller kanoniske URL-er og løser dem til API-en cardIds. En bordgraf kan inkludere tilkoblede kort på andre lesbare tavle; inScope skiller dem. Skjulte aktive blokkere forbli talt gjennom blockedByCountog grafen stopper ved 400 kort. Se grafen API for gjennomgående detaljer.

tavlen separatorer​

Skilletegn er styreeide elementer som deler en listes bestillingsfelt med kort. Deres skrevne ankere kan målrette mot begge typer elementer, slik at en integrasjon kan lage en nøyaktig seksjon og deretter plassere kort rundt den uten å beregne numeriske posisjoner.

const separator = await kanera.separators.create(boardId, listId, {
title: "This week",
color: "blue",
anchor: { side: "before", item: { type: "card", id: cardId } },
});

await kanera.cards.move("MKT-42", {
listId,
anchor: { side: "after", item: { type: "separator", id: separator.id } },
});

await kanera.separators.update(separator.id, { title: "Next up", color: "green" });

Bruk kanera.separators.move for å flytte en separator i forhold til et kort, en annen separator eller en listekant. Sletting av en separator etterlater hvert kort på plass.

Påminnelser og å se på​

Se og påminnelser er den tilkoblede personens egne, så de trenger en personlig nøkkel eller en OAuth-tilkobling. 403. En påminnelse er privat, maksimalt én per kort, og opptil åtte uker fremover.

await kanera.cards.watch("MKT-42");
const state = await kanera.cards.setReminder("MKT-42", new Date("2026-10-16T15:00:00+01:00"));
state.reminder?.remindAt; // "2026-10-16T14:00:00.000Z"

const pending = await kanera.cards.listReminders(); // soonest first, with each card's key, title and url
await kanera.cards.clearReminder("MKT-42");

setReminder erstatter eventuelle eksisterende påminnelser på kortet, inkludert en som allerede er avfyrt. Se Påminnelser.

Hvis du vil høre om svar og omtaler uten å motta webhooks, kan du avspørre innboksen for varslingen. cursor og gi den tilbake som since:

let cursor: string | undefined;
const page = await kanera.cards.pollNotifications({ since: cursor });
for (const item of page.items) console.log(item.summary, item.card?.url);
cursor = page.cursor; // repeat while page.hasMore

Lag flere kort​

kanera.cards.bulk.create oppretter opptil 50 kort på ett tavle i en forespørsel, hver med sin egen liste, etiketter, oppdragsgivere og forfallsdato. Hvert kort er validert før noen er opprettet, så pass en idempotencyKey og hele partiet er trygt å prøve igjen.

const { cards } = await kanera.cards.bulk.create(boardId, [
{ listId, title: "Draft the brief", labelIds: [labelId] },
{ listId, title: "Review with legal", assigneeIds: [userId], dueDateLocalDate: "2026-11-02" },
], { idempotencyKey: crypto.randomUUID() });

kanera.cards.create Tar det samme labelIds, assigneeIds, dueDateLocalDate, og dueDateSlot for et enkelt kort.

Sjekklister​

Lag en sjekkliste med hele innholdet i en forespørsel: elementer med beskrivelser, oppdragsgivere og forfallsdatoer, og ett nivå av undersjekklister under toppnivåelementer. Serveren genererer og kobler hver ID atomisk og returnerer dem, så det er ingenting å slå opp etterpå.

const plan = await kanera.cards.checklists.create("MKT-42", {
title: "Launch",
items: [
{
text: "Prepare release",
description: "Coordinate the release.",
assigneeId: userId,
dueDateLocalDate: "2026-12-01",
subChecklists: [{ title: "Verification", items: [{ text: "Run smoke tests" }, { text: "Confirm rollback" }] }],
},
{ text: "Announce launch" },
],
});

// Add items in order at a position (omit the anchor to append).
await kanera.cards.checklists.addItems("MKT-42", plan.id, [{ text: "Kickoff" }], { afterItemId: null });

// Different changes for chosen items, applied atomically.
const [verification] = plan.subChecklists;
await kanera.cards.checklists.updateItems("MKT-42", verification.items.map((item) => ({ itemId: item.id, changes: { completed: true } })));

// The same assignee or due date on every item of one checklist.
await kanera.cards.checklists.updateAllItems("MKT-42", plan.id, { assigneeId: userId });

// Read the card's checklists without the rest of card detail.
const { checklists } = await kanera.cards.checklists.list("MKT-42");

Undersjekklisteelementer tar bare text og completed, og elementer flyttes bare innenfor sin egen gruppe: mellom sjekklister på toppnivå, eller mellom undersjekklistene til ett overordnet element. En batch valideres i sin helhet før noe er skrevet; en avvist forespørsel er error.options.body.issues navn på det eksakte feltet, som items[0].subChecklists[0].items[1].textUkjente felter blir avvist i stedet for å ignoreres.

Agent kjører​

Når integrasjonen din er en agent som gjør arbeid på et kort, fortell Kanera det startet. Kortflisen viser deretter en levende chip som navngir agenten og jobben, kortdetaljer viser løpet under flyvningen, og terminalutfallet beveger seg inn i aktivitetsfeeden. Ingen må gjette om en jobb fortsatt går.

const run = await kanera.runs.start("MKT-42", {
title: "Drafting launch copy",
summary: "Reading the brief and the last two campaigns.",
externalUrl: "https://github.com/acme/site/pull/318", // optional; where a person can watch it
});

// Every update is a heartbeat. Send one at least every 10 minutes on a long job.
await kanera.runs.heartbeat(run.id);

// Waiting on a person? Say so, and the card's chip turns amber.
await kanera.runs.update(run.id, { status: "blocked", summary: "Need sign-off on the pricing line." });

await kanera.runs.finish(run.id, "succeeded", { summary: "Draft posted as a comment." });

finish tar succeeded, failed, eller cancelled. En terminal status avslutter kjøringen og gjør den uforanderlig, så en senere update På den feiler med en CONFLICT feil — sjekk error.status === 409 Hvis en reprøve kunne lande etter din egen finish.

En live run uten hjerteslag i femten minutter er merket stalled av Kanera, så en krasjet agent kan ikke forlate et kort som viser "arbeider" for alltid. En stoppet løp er ikke avsluttet: agenten kan fortsatt komme tilbake og lukke den, eller sette status: "running" å gjenoppta.

Bruk kanera.runs.list(card) før du starter så to agenter ikke kjøre samme kort, { includeEnded: true } for hele historien, og kanera.runs.get(runId) Lese en runde igjen.

Registrer webhooks​

En administrator administrerer hvert endepunkt i et arbeidsområde. En ikke-admin skrive-kompatible credential eller interaktiv OAuth agent kan også registrere endepunkter, men bare ser de sin egen tilkobling opprettet. Dette er nyttig når en agent trenger hendelsen tilbakekall uten arbeidsområde-admin myndighet.

const endpoint = await kanera.webhookEndpoints.create(workspaceId, {
name: "Release agent",
url: "https://agent.example.com/kanera",
eventTypes: ["card:updated", "comment:created"], // [] means every event
});

// The secret is returned only now (and after rotateSecret).
await saveSecret(endpoint.secret);

const deliveries = await kanera.webhookEndpoints.deliveries(workspaceId, endpoint.id);

Tilkoblings-scoped endepunkter returnerer scope: "connection"; admin-opprettede endepunkter returnerer scope: "workspace"Ressursen gir også list, update, rotateSecret, retryDelivery, og delete. Se Webhooks for nyttelastverifisering og leveringssemintik.

Paginering​

Hvert listeendepunkt er avgrenset; det er ingen "gi meg hele tavlen" -anrop. Den vanlige integrasjonsfeilen leser side en og behandler det som hele settet, så iterasjon er standardformen:

for await (const board of kanera.boards.iterate()) { /* … */ }

const firstFifty = await kanera.comments.iterate("MKT-42").all(50);

// Or drive the pages yourself.
let cursor: string | undefined;
do {
const page = await kanera.comments.list("MKT-42", { cursor });
cursor = page.nextCursor ?? undefined;
} while (cursor);

Feil​

import { KaneraApiError } from "@kanera/sdk";

try {
await kanera.cards.update("MKT-42", { title: "New" });
} catch (error) {
if (error instanceof KaneraApiError && error.isForbidden) {
// A read-only credential, or no Editor access to this board. Retrying will not help.
}
}

KaneraApiError Bærer HTTP status, Kanera's stabile feil code, og vakter for sakene verdt forgrening på: isUnauthenticated, isForbidden, isNotFound, isRateLimited, isRetryable. Transportfeil øker KaneraConnectionError.

Retriever og idempotens​

Leser og DELETE/PUT blir automatisk forsøkt på hastighetsgrenser og forbigående oppstrømsfeil, med eksponentiell tilbakeslag, full jitter og Retry-After Det er en ære når Kanera sender den.

Mutasjoner blir ikke forsøkt på nytt med mindre du oppgir en idempotensnøkkel, fordi en forsøk etter en tvetydig feil ville skape et andre kort eller legge inn en annen kommentar. Tilfør en og API spiller det første resultatet i stedet for å gjenta skrivingen:

await kanera.comments.create("MKT-42", { body: "Deployed." }, {
idempotencyKey: crypto.randomUUID(),
});

Bekreft webhooks​

parseWebhook verifiserer signaturen og returnerer den analyserte hendelsen, eller kaster. Den kaster i stedet for å returnere en boolsk, slik at en handler ikke kan glemme å sjekke før nyttelasten brukes:

import { parseWebhook } from "@kanera/sdk";

app.post("/kanera", async (req, res) => {
const event = await parseWebhook({
secret: process.env.KANERA_WEBHOOK_SECRET!,
payload: req.rawBody, // the exact bytes; re-serialised JSON will not verify
headers: req.headers,
});
// event.type, event.workspaceId, event.data
res.sendStatus(204);
});

Underskriften dekker {timestamp}.{body}, og tidsstempelet sjekkes mot et fem minutters vindu - konfigurerbart - for å binde avspilling. Den bruker Web Crypto, så det fungerer i arbeidere og kantkjøringstider, samt Node. Se Webhooks for endepunktoppsett og hendelseskatalogen.

Valg​

new Kanera({
apiKey,
baseUrl: "https://api.kanera.app", // your own origin when self-hosting
timeoutMs: 30_000,
maxRetries: 2,
organisationId, // pin an identity-wide personal credential to one organisation
userAgent: "acme-sync/2.1", // appended to the SDK's own User-Agent
onRetry: ({ attempt, delayMs }) => log.warn({ attempt, delayMs }),
fetch: myFetch, // supply your own agent or proxy
});

Escape luke​

API-en beveger seg raskere enn den maskinskrevne overflaten, og ingenting er portet bak en innpakning:

const result = await kanera.http.post<MyType>("/api/v1/some/new/endpoint", body);

Et notat på nettlesere​

Pakken kjører i en nettleser, men bruker det betyr å sende en API-nøkkel til klienten. Bare gjør det i en pålitelig førstepartskontekst. For alt brukervendt, ring Kanera fra serveren din.