Pulse
Back
API reference

Build on Pulse

Every entry, project, category, and work memory in your workspace is reachable two ways: a 13-tool MCP server for AI agents (19 with work memory switched on), and a REST API under /api/v1 for scripts, cron jobs, and dashboards. Both are thin wrappers over the same data layer, so reads and writes stay consistent whichever one you use.

Authentication

Every request — MCP or REST — carries a bearer token. Create one from Settings → Developers once signed in.

Authorization: Bearer psk_...
REST accepts only a psk_... API token.
MCP accepts a psk_... token or an OAuth 2.1 access token — used for the Claude.ai custom connector, which authorizes over OAuth instead of a pasted token.
A token always resolves to one user. Every read and write is scoped to that user’s own data — an admin token can additionally see workspace-wide catalogs (members) where noted below.

MCP server

A remote, streamable-HTTP MCP server. Point any MCP client — Claude Code, Codex, or Claude.ai as a custom connector — at:

{ "pulse": { "url": "https://pulse.transmit.work/api/mcp", "headers": { "Authorization": "Bearer psk_..." } } }
pulse_whoami
Read-only
Return the authenticated user’s profile.
No parameters.
Returns Profile: id, name, email, role, team, experience, companyId, emailVerified, tools[].
pulse_list_entries
Read-only
List the caller’s own time entries, newest first, paginated.
Parameters
scope · "week" | "month" | "last_month"
Reporting period. Defaults to the current week (Mon–Sun).
limit · number
Max entries to return, 1–200. Default 50.
offset · number
Entries to skip, for pagination. Default 0.
Returns { scope, total, count, offset, limit, has_more, next_offset, items[] } — each item has id, date, category, categoryLabel, tool, project, description, start, end, durationMin, pauseMin, kind, source, note.
pulse_get_summary
Read-only
The caller’s balance for the period: minutes used vs. quota.
Parameters
scope · "week" | "month" | "last_month"
Reporting period. Defaults to the current week.
Returns { scope, usedMin, quotaMin, percentUsed, remainingMin, entryCount, timeUnit, categories[] } — categories[] is a per-category minutes breakdown, sorted descending.
pulse_list_categories
Read-only
List the workspace’s active activity categories.
No parameters.
Returns { items: [{ id, label, color }] }
pulse_update_category
WriteAdmin-only
Rename an activity category.
Parameters
category · string · required
Category id, or exact (case-insensitive) label.
label · string · required
New label.
Returns { ok: true, id, message }
pulse_list_tools
Read-only
List the tools/sources assigned to the caller.
No parameters.
Returns { items: [{ id, label, purpose, domain }] } — only tools assigned to the caller.
pulse_update_tool
WriteAdmin-only
Rename a tool/source.
Parameters
tool · string · required
Tool id, or exact (case-insensitive) label.
label · string · required
New label.
Returns { ok: true, id, message }
pulse_list_projects
Read-only
List the projects assigned to the caller.
No parameters.
Returns { items: [{ id, name }] } — only projects assigned to the caller.
pulse_create_project
WriteAdmin-only
Create a new project on the workspace.
Parameters
name · string · required
Project name (e.g. "Migration"). Appended to the end of the active list.
Returns { ok: true, id, message } on success, or { isError: true } with a plain-text reason.
pulse_update_project
WriteAdmin-only
Rename a project. There’s no archive/delete tool for projects (or categories, or tools) — that’s an intentional, in-app-only action in Settings, not something an agent can do in one call.
Parameters
project · string · required
Project id, or exact (case-insensitive) name.
name · string
New name. Only fields you pass are changed.
Returns { ok: true, id, message }
pulse_list_members
Read-onlyAdmin-only
List workspace members.
No parameters.
Returns { items: [{ id, name, email, role, team, pending, emailVerified }] }. Errors for non-admin tokens.
pulse_log_entry
Write
Log a time entry on the caller’s own timesheet. Recorded directly and immediately visible — no approval step. Entries logged this way are tagged source: "agent".
Parameters
category · string · required
Prefer the readable label (e.g. "Dev") from pulse_list_categories — the id also works.
tool · string · required
Prefer the readable label (e.g. "Claude Code") from pulse_list_tools — the id also works.
description · string · required
What the work was.
durationMin · number · required
Duration in minutes.
date · string · required
YYYY-MM-DD — the day the work happened. Not defaulted, so a backfilled entry never gets silently dated to today.
start · string
Optional start time, HH:MM.
end · string
Optional end time, HH:MM.
note · string
Optional free-text note — e.g. a PR URL or issue id, for traceability.
project · string
Project label or id. Sets project attribution in the same call.
Returns { ok: true, id, message: "Entry logged." }
pulse_update_entry
Write
Update fields on an existing entry owned by the caller. Only the fields you pass change.
Parameters
entry_id · string · required
The entry id, from pulse_list_entries.
category · string
New category — label or id.
tool · string
New tool — label or id.
project · string | null
New project — label or id; pass null to clear.
description · string
New description.
durationMin · number
New duration in minutes.
date · string
YYYY-MM-DD.
start · string | null
HH:MM, or null to clear.
end · string | null
HH:MM, or null to clear.
note · string | null
Or null to clear.
Returns { ok: true, id, message: "Entry updated." }
The six work-memory tools below are opt-in, and scoped by role. They’re off for new workspaces. An admin enables the feature under Settings → Lab → Work memory (Off / Admins only / Everyone), and sets separately, under Agent capture, whose agents may use these tools — so a workspace can let every engineer’s agent file suggestions while only admins review them. While a token’s role is excluded the tools don’t appear in tools/list at all (rather than appearing and failing), and the REST endpoints return 403 — or 404 when the feature is off for the whole workspace. If your agent can’t see them, those settings are why.
pulse_suggest_memory
Write
Propose something durable the agent noticed while working — a decision made, a constraint discovered, a migration completed. It lands as status: "suggested" for a human to confirm, edit, or dismiss in the app, so it is safe to offer one when unsure. Routine activity (typo fixes, running tests, ordinary commits) should never produce a memory — the timeline is already exhaustive; memory stays selective.
Parameters
type · string · required
decision | learning | outcome | milestone | blocker.
title · string · required
The decision or lesson itself, stated plainly.
summary · string · required
A sentence or two that still makes sense out of context.
detail · string
Longer context — alternatives weighed, caveats, links.
occurredOn · string · required
YYYY-MM-DD — the day it happened.
project · string
Project name or id. Omit for a workspace-level memory.
confidence · number
0-1 or 0-100.
entryIds · string[]
Ids of the caller’s own entries this came from, for provenance.
Returns { ok: true, id, status: "suggested", message }
pulse_create_memory
Write
Save a memory directly as confirmed. Only for when the user explicitly asked to remember something (“remember that we chose Vercel”) — an inference the agent made on its own belongs in pulse_suggest_memory.
Parameters
Same as pulse_suggest_memory, minus confidence.
Returns { ok: true, id, status: "confirmed", message }
pulse_list_memories
Read-only
The workspace’s durable knowledge, newest first. Returns confirmed memories by default, so an agent reading back gets settled decisions rather than untriaged guesses. Only confirmed memories are workspace-wide; suggestions stay visible to whoever captured them (and admins).
Parameters
status · string
confirmed (default) | suggested | dismissed | any.
type · string
Filter to one kind.
project · string
Project name or id.
from · string
Earliest occurredOn (YYYY-MM-DD).
to · string
Latest occurredOn (YYYY-MM-DD).
limit · number
Default 50, max 200.
offset · number
For pagination.
Returns { total, count, offset, limit, has_more, next_offset, items } — each item carries its provenance: type, title, summary, detail, status, confidence, occurredOn, project, createdBy { userId, name, source }, and entryIds.
pulse_search_memories
Read-only
Keyword search across title, summary, and detail — for questions like “what did we learn about Supabase auth?”. Matching is keyword-based, not semantic: it returns candidates generously and the calling model does the ranking.
Parameters
query · string · required
Keywords. Prefer distinctive nouns over a full sentence.
status · string
any (default) | confirmed | suggested | dismissed.
type · string
Filter to one kind.
project · string
Project name or id.
from · string
Earliest occurredOn (YYYY-MM-DD).
to · string
Latest occurredOn (YYYY-MM-DD).
limit · number
Default 25, max 200.
offset · number
For pagination.
Returns { query, total, count, offset, limit, has_more, next_offset, items }
pulse_update_memory
Write
Refine a memory the caller captured that a human hasn’t confirmed yet. Once confirmed it is the team’s record, and only an admin can change it.
Parameters
memory_id · string · required
The memory id, from pulse_list_memories.
type · string
New kind.
title · string
New title.
summary · string
New summary.
detail · string | null
Or null to clear.
occurredOn · string
YYYY-MM-DD.
project · string | null
Name or id; null to clear.
confidence · number
0-1 or 0-100.
Returns { ok: true, id, message: "Memory updated." }
pulse_dismiss_memory
Write
Retract a suggestion that turned out to be wrong. Works only on the caller’s own memories that nobody has confirmed yet, and sets status: "dismissed" rather than deleting anything.
Parameters
memory_id · string · required
The memory id.
Returns { ok: true, id, message: "Memory dismissed." }
There is no pulse_confirm_memory — by design. Confirming is what turns an agent’s inference into organizational truth that future agents read back as settled fact, so it stays a deliberate in-app action (the same way deleting an entry does). An agent can still retract its own untriaged suggestion with pulse_dismiss_memory.

No delete tool exists, by design — every entry an agent writes stays visible and editable, never silently removed.

REST API

Bearer-token endpoints under:

https://pulse.transmit.work/api/v1

REST covers the same ground as MCP: reading everything, creating and updating entries, renaming categories and tools, and listing, creating, or renaming projects. There’s no archive/delete for projects, categories, or tools on either surface — an intentional, in-app-only action in Settings.

GET/api/v1/me
Read-only
The authenticated user’s profile.
Returns Profile: id, name, email, role, team, experience, companyId, emailVerified, tools[]. 404 if not found.
GET/api/v1/entries
Read-only
List the caller’s own time entries, newest first, paginated.
Query parameters
scope · "week" | "month" | "last_month"
Defaults to the current week.
limit · number
1–200. Default 50.
offset · number
Default 0.
Returns { scope, total, count, offset, limit, has_more, next_offset, items[] }
POST/api/v1/entries
Write
Create a time entry on the caller’s own timesheet, tagged source: "api" — distinct from an entry typed into the app ("manual") or logged by an agent over MCP ("agent").
Request body (JSON)
category · string · required
Label or id.
tool · string · required
Label or id.
description · string · required
What the work was.
durationMin · number · required
Duration in minutes.
project · string
Project label or id. Sets project attribution in the same call.
date · string · required
YYYY-MM-DD — the day the work happened. Not defaulted.
start · string
HH:MM.
end · string
HH:MM.
note · string
Free-text note.
Returns 201 { ok: true, id } on success; 400 { error } on invalid input.
PATCH/api/v1/entries/:id
Write
Update fields on an existing entry owned by the caller — :id is the entry id, from GET /api/v1/entries. Only the fields you pass change, same as pulse_update_entry.
Request body (JSON)
category · string
New category — label or id.
tool · string
New tool — label or id.
project · string | null
New project — label or id; pass null to clear.
description · string
New description.
durationMin · number
New duration in minutes.
date · string
YYYY-MM-DD.
start · string | null
HH:MM, or null to clear.
end · string | null
HH:MM, or null to clear.
note · string | null
Or null to clear.
Returns { ok: true, id }; 404 if the entry doesn’t exist or isn’t the caller’s; 400 on invalid input.
GET/api/v1/summary
Read-only
The caller’s balance for the period.
Query parameters
scope · "week" | "month" | "last_month"
Defaults to the current week.
Returns { scope, usedMin, quotaMin, percentUsed, remainingMin, entryCount, timeUnit, categories[] }
GET/api/v1/categories
Read-only
The workspace’s active activity categories.
Returns { items: [{ id, label, color }] }
PATCH/api/v1/categories/:id
WriteAdmin-only
Rename an activity category — :id is the category id, from GET /api/v1/categories. Same as pulse_update_category.
Request body (JSON)
label · string · required
New label.
Returns { ok: true, id }; 404 if the category doesn’t exist; 403 for non-admins; 400 on invalid input.
GET/api/v1/tools
Read-only
The tools/sources assigned to the caller.
Returns { items: [{ id, label, purpose, domain }] } — only tools assigned to the caller.
PATCH/api/v1/tools/:id
WriteAdmin-only
Rename a tool/source — :id is the tool id, from GET /api/v1/tools. Same as pulse_update_tool.
Request body (JSON)
label · string · required
New label.
Returns { ok: true, id }; 404 if the tool doesn’t exist; 403 for non-admins; 400 on invalid input.
GET/api/v1/projects
Read-only
The projects assigned to the caller.
Returns { items: [{ id, name }] } — only projects assigned to the caller.
POST/api/v1/projects
WriteAdmin-only
Create a new project on the workspace.
Request body (JSON)
name · string · required
Project name (e.g. "Migration"). Appended to the end of the active list.
Returns 201 { ok: true, id } on success; 403 { error: "Admins only." } for non-admins; 400 { error } on invalid input.
PATCH/api/v1/projects/:id
WriteAdmin-only
Rename a project — :id is the project id, from GET /api/v1/projects. Same as pulse_update_project. No archive/delete endpoint exists — that’s an intentional, in-app-only action in Settings.
Request body (JSON)
name · string · required
New name.
Returns { ok: true, id }; 404 if the project doesn’t exist; 403 for non-admins; 400 on invalid input.
GET/api/v1/members
Read-onlyAdmin-only
Workspace members — id, name, email, role, team, pending, emailVerified.
Returns 200 { items: [...] } for admins; 403 { error: "Admins only." } otherwise.
GET/api/v1/memories
Read-only
Work memories, newest first — ?status= (confirmed by default),?type=, ?project=, ?from=, ?to=, ?limit=, ?offset=. Adding ?q= switches to keyword search across title, summary, and detail. Mirrors pulse_list_memories / pulse_search_memories.
Returns 200 { total, count, offset, limit, has_more, next_offset, items }. With ?q= the response also carries query.
POST/api/v1/memories
Write
Capture a memory. Body: type, title, summary, occurredOn (all required), plus optional detail, project, confidence, entryIds. Defaults to a suggestion; send status: "confirmed" only when the user explicitly asked to remember it.
Returns 201 { ok: true, id, status }
PATCH/api/v1/memories/:id
Write
Edit a memory you captured that nobody has confirmed yet — a key you omit stays untouched, an explicit null clears detail or project. Sending status: "dismissed" retracts it; that is the only status change available here, since confirming happens in the app.
Returns 200 { ok: true, id }; 403 when the memory isn’t yours or is already confirmed.
Full setup walkthroughs (connecting Claude Code, Codex, or the Claude.ai connector) live in the Help documentation. Something look wrong here? Tell us.