Clients

The RedmineClient and its sub-clients, one per resource of the Redmine API.

RedmineClient takes the URL of your Redmine server and the API key. It doesn't have methods itself: the endpoints are grouped into one sub-client per resource, e.g. client.issuesClient or client.projectsClient.

import { RedmineClient } from "redmine-api-client";

const client = new RedmineClient("https://redmine.example.com", { key: process.env.REDMINE_API_KEY! });

const { issue } = await client.issuesClient.getIssue(42);
const { project } = await client.projectsClient.getProject("my-project");

Each sub-client matches a tag of the API Reference, which documents the parameters and responses of each method.

How the methods work

The methods follow the same patterns across all sub-clients:

  • Names follow the action and the resource: getIssues (list), getIssue (one), createIssue, updateIssue, deleteIssue.
  • Path parameters come first, as plain arguments: getIssue(42), getWikiPage("my-project", "Start"). Projects take their ID or identifier.
  • Request bodies are wrapped like in the Redmine API: createIssue({ issue: { … } }).
  • Options come last, e.g. filters and include for associated data: getIssue(42, { include: [IssueQueryInclude.Journals] }).
  • Responses are wrapped as well: getIssue returns { issue }, updateIssue and deleteIssue return nothing.
  • Lists return a pager instead of a promise, see Pagination.
  • Properties use camelCase (issue.createdOn, projectId). The client converts them from and to the snake_case of the API (created_on, project_id).
import { IssueQueryInclude } from "redmine-api-client";

// Read, with associated data
const { issue } = await client.issuesClient.getIssue(42, {
  include: [IssueQueryInclude.Journals, IssueQueryInclude.Attachments],
});

// Create
const { issue: created } = await client.issuesClient.createIssue({
  issue: { projectId: 1, subject: "Printer is on fire", priorityId: 4 },
});

// Update (adds a note to the history of the issue)
await client.issuesClient.updateIssue(created.id, {
  issue: { notes: "Fire is out, printer is not." },
});

// Delete
await client.issuesClient.deleteIssue(created.id);

Issues and projects

Sub-clientMethods
client.issuesClientgetIssues, getIssue, createIssue, updateIssue, deleteIssue, addIssueWatcher, removeIssueWatcher
client.journalsClientupdateJournal, to change the notes of an issue's history entry
client.issueRelationsClientgetIssueRelations, createIssueRelation, getIssueRelation, deleteIssueRelation
client.issueCategoriesClientgetProjectIssueCategories, createIssueCategory, getIssueCategory, updateIssueCategory, deleteIssueCategory
client.projectsClientgetProjects, getProject, createProject, updateProject, deleteProject, archiveProject, unarchiveProject, closeProject, reopenProject
client.versionsClientgetProjectVersions, createVersion, getVersion, updateVersion, deleteVersion

Issues are updated with updateIssue, also to add notes. Changes and notes show up as journals, which getIssue returns with include: [IssueQueryInclude.Journals].

await client.issuesClient.addIssueWatcher(42, { userId: 7 });

Time tracking

Sub-clientMethods
client.timeEntriesClientgetTimeEntries, getTimeEntry, createTimeEntry, updateTimeEntry, deleteTimeEntry
await client.timeEntriesClient.createTimeEntry({
  timeEntry: { issueId: 42, hours: 1.5, comments: "Fought the printer" },
});

Users and permissions

Sub-clientMethods
client.usersClientgetUsers, getUser, createUser, updateUser, deleteUser (mostly admin only)
client.myAccountClientgetMyAccount, updateMyAccount, the account of the API key's user
client.groupsClientgetGroups, getGroup, createGroup, updateGroup, deleteGroup, addGroupUser, removeGroupUser (admin only)
client.rolesClientgetRoles, getRole
client.membershipsClientgetProjectMemberships, createProjectMembership, getMembership, updateMembership, deleteMembership

getUser also takes "current" for the user of the API key:

const { user } = await client.usersClient.getUser("current");

Content

Sub-clientMethods
client.wikiPagesClientgetProjectWikiPages, getWikiPage, getWikiPageVersion, updateWikiPage (also creates pages), deleteWikiPage
client.newsClientgetNews, getProjectNews, getNewsItem, createNews, createProjectNews, updateNews, deleteNews
client.attachmentsClientuploadFile, getAttachment, updateAttachment, deleteAttachment
client.filesClientgetProjectFiles, createProjectFile
client.searchClientsearch, searchProject

Files are uploaded in two steps: uploadFile returns a token, which you then attach to an issue, a wiki page or a project:

import { readFile } from "node:fs/promises";

const { upload } = await client.attachmentsClient.uploadFile(await readFile("report.pdf"), {
  filename: "report.pdf",
  contentType: "application/pdf",
});

await client.issuesClient.updateIssue(42, {
  issue: { uploads: [{ token: upload.token, filename: "report.pdf" }] },
});

Settings

These read the configuration of the Redmine server, e.g. to fill select fields:

Sub-clientMethods
client.trackersClientgetTrackers
client.issueStatusesClientgetIssueStatuses
client.enumerationsClientgetIssuePriorities, getTimeEntryActivities, getDocumentCategories
client.customFieldsClientgetCustomFields (admin only)
client.savedQueriesClientgetQueries

On this page