npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@worksection/api-client

v2.1.2

Published

API client library for Worksection

Readme

Worksection Node.js API Client

Official TypeScript/Node.js client library for the Worksection API.

Requirements

  • Node.js 18+
  • TypeScript 5+ (for TypeScript usage)

Installation

npm install @worksection/api-client

Authentication

The client supports two authentication methods: API Key (admin access) and OAuth2 (user access).

API Key

Get your API key from your Worksection account settings.

import { Client } from '@worksection/api-client';

const client = new Client('https://your-account.worksection.com');
client.setApiKey('your-api-key');

OAuth2

import { Client } from '@worksection/api-client';

const client = new Client('https://your-account.worksection.com');
client.setClient({
  client_id:     'your-client-id',
  client_secret: 'your-client-secret',
  redirect_uri:  'https://your-app.com/callback',
  scope:         ['projects_read', 'tasks_read', 'tasks_write'],
  // defaults:
  auth_url:      'https://worksection.com/oauth2/authorize',
  token_url:     'https://worksection.com/oauth2/token',
  refresh_url:   'https://worksection.com/oauth2/refresh',
});

// Step 1: redirect the user to the authorization URL
const state = crypto.randomUUID();
const authUrl = client.oauth.getAuthorizationUrl(state);
res.redirect(authUrl);

// Step 2: exchange the authorization code for an access token (in your callback handler)
if (req.query.state !== state) throw new Error('Invalid state');
const token = await client.oauth.fetchAccessTokenByAuthCode(req.query.code);
client.setAccessToken(token);

// The client will automatically refresh the access token using the refresh token when needed.

Available OAuth2 scopes

projects_read, projects_write, tasks_read, tasks_write, costs_read, costs_write, tags_read, tags_write, comments_read, comments_write, files_read, files_write, users_read, users_write, contacts_read, contacts_write, administrative

Usage

Projects

// List all projects
const projects = await client.projects.list();

// Filter projects: active | pending | archived
const active = await client.projects.list({ filter: 'active' });

// Get a single project
const project = await client.projects.get(projectId);

// Create a project
const project = await client.projects.create('Project title', {
  email_manager: '[email protected]',
  dateend:       '2025-12-31',
});

// Update a project
const project = await client.projects.update(projectId, { title: 'New title' });

// Archive / activate
await client.projects.close(projectId);
await client.projects.activate(projectId);

// Manage members
await client.projects.addMembers(projectId, ['[email protected]']);
await client.projects.removeMembers(projectId, ['[email protected]']);

// Project groups (folders)
const groups = await client.projects.groups();
const group  = await client.projects.createGroup('Group name');

// Tags
const tags = await client.projects.tags();
const tags = await client.projects.createTags(groupId, 'Tag name');
await client.projects.updateTags(projectId, [1, 2], [3]);

// Tag groups
const tagGroups = await client.projects.tagGroups();
const tagGroup  = await client.projects.createTagGroup('Group name', 'public');

// Custom fields
const fields = await client.projects.customFields();

Tasks

// List tasks in a project
const tasks = await client.tasks.list(projectId);

// List all tasks across all projects
const tasks = await client.tasks.list();

// Get a single task (with extra data)
const task = await client.tasks.get(taskId, { extra: 'text,files,comments' });

// Create a task
const task = await client.tasks.create(projectId, 'Task title', {
  email_user_to: '[email protected]',
  dateend:       '2025-06-30',
  priority:      'high',
});

// Create a subtask
const subtask = await client.tasks.create(projectId, 'Subtask title', {
  id_parent: parentTaskId,
});

// Update a task
const task = await client.tasks.update(taskId, { title: 'New title' });

// Complete / reopen
await client.tasks.complete(taskId);
await client.tasks.reopen(taskId);

// Search tasks
const tasks = await client.tasks.search({ email_user_to: '[email protected]', status: 'active' });

// Subscribers
await client.tasks.subscribe(taskId, '[email protected]');
await client.tasks.unsubscribe(taskId, '[email protected]');

// Tags
const tags = await client.tasks.tags();
const tags = await client.tasks.createTags(groupId, 'Tag name');
await client.tasks.updateTags(taskId, [1, 2], [3]);

// Tag groups
const tagGroups = await client.tasks.tagGroups();
const tagGroup  = await client.tasks.createTagGroup('Group name', 'public');

// Custom fields
const fields = await client.tasks.customFields();

Comments

// List comments on a task
const comments = await client.comments.list(taskId);

// List comments with attached files
const comments = await client.comments.list(taskId, { extra: 'files' });

// Create a comment
const comment = await client.comments.create(taskId, 'Comment text', {
  email_user_from: '[email protected]',
  hidden:          1,  // internal comment
});

Members

// List all account members
const members = await client.members.list();

// Invite a new member
const member = await client.members.create('[email protected]', {
  first_name: 'John',
  last_name:  'Doe',
  title:      'Developer',
  role:       'user',  // user | manager | admin
});

// Member groups (teams)
const groups = await client.members.groups();
const group  = await client.members.createGroup('Backend Team');

// Work schedules
const schedules = await client.members.schedule({
  users:     ['[email protected]'],
  datestart: '2025-01-01',
  dateend:   '2025-01-31',
});

await client.members.updateSchedule({
  '[email protected]': { mon: 8, tue: 8, wed: 8, thu: 8, fri: 8 },
});

User (OAuth2 only)

// Get the current authenticated user's profile
const profile = await client.user.profile();

// Timer management for the current user
const timer = await client.user.timer();              // get active timer (or null)
await client.user.startTimer(taskId);                 // start timer on a task
await client.user.stopTimer('Done for today');        // stop and log with a comment
await client.user.discardTimer();                     // discard without logging

Costs

// List expense records
const costs = await client.costs.list();

// Filter by project, task, or date range
const costs = await client.costs.list({
  id_project: projectId,
  datestart:  '2025-01-01',
  dateend:    '2025-01-31',
});

// Get totals/summary
const total = await client.costs.total({ id_project: projectId });

// Get totals broken down by project and task
const total = await client.costs.total({ extra: 'projects,tasks' });

// Create an expense record
const costId = await client.costs.create(taskId, {
  time:            90,
  money:           50,
  email_user_from: '[email protected]',
  comment:         'Design work',
  date:            '15.06.2025',
});

// Update / delete
await client.costs.update(costId, { time: 120, comment: 'Updated' });
await client.costs.delete(costId);

Timers (admin)

// List all active timers across the account
const timers = await client.timers.all();

// Stop a specific timer
await client.timers.stop(timerId);

Contacts

// List all contacts
const contacts = await client.contacts.list();

// Create a contact
const contact = await client.contacts.create('[email protected]', 'Jane Smith', {
  title:   'CEO',
  group:   groupId,
  phone:   '+1 555 000 0000',
  address: '123 Main St',
});

// Contact groups
const groups = await client.contacts.groups();
const group  = await client.contacts.createGroup('VIP Clients');

Events

// Get recent events for the whole account
const events = await client.events.list('7d');

// Get events for a specific project
const events = await client.events.list('30d', projectId);

Files

// List files on a task or project
const files = await client.files.list({ id_task: taskId });
const files = await client.files.list({ id_project: projectId });

// Upload files
const uploaded = await client.files.upload(['/path/to/file.pdf']);

// Download a file
const downloaded = await client.files.download(fileId, '/path/to/save.pdf');

Webhooks

// List all webhooks
const webhooks = await client.webhook.list();

// Create a webhook
// Available events: post_task, post_comment, post_project,
//                   update_task, update_comment, update_project,
//                   delete_task, delete_comment, close_task
const id = await client.webhook.create(
  'https://your-app.com/webhook',
  ['post_task', 'update_task', 'close_task'],
  { projects: [projectId] },
);

// Delete a webhook
await client.webhook.delete(id);

Error handling

import { ResponseException, UnauthorizedException } from '@worksection/api-client';

try {
  const task = await client.tasks.get(taskId);
} catch (e) {
  if (e instanceof UnauthorizedException) {
    // Invalid or expired token
  } else if (e instanceof ResponseException) {
    // API returned an error response
    console.error(e.message, e.statusCode);
  }
}

License

MIT