whoworked
v0.5.0
Published
Official TypeScript SDK for the WhoWorked API.
Maintainers
Readme
whoworked
Official TypeScript SDK for the WhoWorked API.
npm install whoworkedQuick start
import { WhoWorked } from "whoworked";
const client = new WhoWorked({
apiKey: process.env.WHOWORKED_API_KEY,
});
const page = await client.entries.list({
workspace_id: "wsp_01HQ...",
});
for (const entry of page.data) {
console.log(entry.description, entry.duration_seconds);
}Authentication
The SDK accepts either an API key or an OAuth access token.
// Server-side, your own workspace:
const client = new WhoWorked({ apiKey: process.env.WHOWORKED_API_KEY });
// Third-party integration, end-user's workspace:
const client = new WhoWorked({ accessToken: oauthTokens.access_token });
// Rotate tokens after refresh:
client.setAccessToken(newAccessToken);Get an API key from your workspace settings. For OAuth integrations, see OAuth flow below.
Pagination
List endpoints return a single page plus a cursor. Use .paginate(...) for
auto-pagination:
for await (const entry of client.entries.list.paginate({ workspace_id })) {
console.log(entry.id);
}Or page manually:
const page = await client.entries.list({ workspace_id, limit: 100 });
if (page.pagination.has_more) {
const next = await client.entries.list({
workspace_id,
cursor: page.pagination.next_cursor,
});
}Errors
Errors are typed and instanceof-checkable:
import {
WhoWorkedError,
RateLimitError,
ValidationError,
NotFoundError,
AuthenticationError,
} from "whoworked";
try {
await client.entries.create({ workspace_id, body });
} catch (e) {
if (e instanceof RateLimitError) {
await sleep(e.retryAfter * 1000);
} else if (e instanceof ValidationError) {
console.error("Bad request:", e.message, e.requestId);
} else if (e instanceof WhoWorkedError) {
console.error("API error:", e.code, e.requestId);
}
}All errors expose .status, .code, .message, .requestId, .docsUrl.
Include the requestId when reporting bugs — we use it to look up server
logs.
Retries
The SDK retries automatically on 429 (honoring Retry-After) and 5xx,
with exponential backoff + jitter. Configure with maxRetries:
const client = new WhoWorked({
apiKey: process.env.WHOWORKED_API_KEY,
maxRetries: 5, // default 2
});OAuth flow
For third-party integrations that need access to other users' workspaces, use the OAuth authorization code + PKCE flow:
import { OAuth } from "whoworked";
// 1. On a "Connect WhoWorked" button click, build the authorize URL:
const { url, codeVerifier, state } = await OAuth.startAuth({
clientId: "oauth_app_...",
redirectUri: "https://yourapp.com/oauth/callback",
scopes: ["entries:read", "entries:write"],
});
// Save `codeVerifier` and `state` (e.g., in a session cookie).
// Redirect the user to `url`.
// 2. In your callback handler:
const code = new URL(request.url).searchParams.get("code");
const tokens = await OAuth.exchangeCode({
code,
codeVerifier, // recovered from session
clientId: "oauth_app_...",
redirectUri: "https://yourapp.com/oauth/callback",
});
// { access_token, refresh_token, expires_in, token_type, scope }
// 3. Use the access token:
const client = new WhoWorked({ accessToken: tokens.access_token });
// 4. Refresh when the access token expires:
const fresh = await OAuth.refresh({
refreshToken: tokens.refresh_token,
clientId: "oauth_app_...",
});
client.setAccessToken(fresh.access_token);Runtimes
- Node 18+
- Browsers (modern,
globalThis.fetch+crypto.subtle) - Cloudflare Workers
- Vercel Edge
- Deno
- Bun
Examples
See examples/ for runnable scripts.
License
Proprietary — Copyright (c) 2025 WhoWorked. All rights reserved. See LICENSE.md.
