Skip to content
shuffl

Searches the public product guides only. Nothing from a workspace is read, and questions are not saved.

Reference

SDK and CLI changelog

What changed in each version of @shuffl/sdk, @shuffl/cli and @shuffl/api-contracts, and how versions and breaking changes work.

For Developers who use the SDK, CLI or API contracts

On this page

App links open your signed-in workspace. Check the selected workspace before making changes.

Versions and breaking changes

The SDK, the CLI and the API contracts share one version number and are released together. Upgrade the SDK and CLI at the same time, and pin an exact version in your project.

While the major version is 0, a minor release such as 0.2.0 to 0.3.0 can rename or remove operations and fields. A patch release such as 0.2.0 to 0.2.1 never does. Each version below lists breaking changes first, under Breaking. Read them before you upgrade.

The hosted API always runs the newest contract. An older SDK or CLI keeps working for every operation that hasn’t changed, but a call to an operation or field that was renamed or removed fails until you upgrade.

Release candidates, such as 0.4.0-rc.1, are published under the next tag. Install one with @shuffl/sdk@next. shuffl --version prints the version you have.

Shell
npm install @shuffl/sdk@0.7.6 @shuffl/cli@0.7.6
shuffl --version

0.7.6 (2026-10-18)

Added

  • Mentees choose their mentor: mentorship.programs.save takes menteesChoose. In such a program mentorship.mine returns each waiting mentee's choices (up to three mentors with topics and reasons) and the mentor they requested; mentorship.mentors.choose (mentorship.chooseMentor, programId, mentorId) asks that mentor. Mentors see requests in mentorship.mine and answer with mentorship.requests.answer (mentorship.answerRequest, decision accept or pass). Program summaries return menteesChoose and requested; pairs can be requested.
  • Session notes: mentorship.sessions.save (mentorship.saveSession, pairId, heldOn, notes, nextStep, optional sessionId) and mentorship.sessions.remove (mentorship.removeSession). Each pair in mentorship.mine returns its sessions, a prep (the newest nextStep, openGoals, questions and stage) and its nextMeeting. Only the two people in the pair read notes. Keys with self:write.
  • Calendar targets take mentorship_pair (a pair id) for Pick a time between a mentor and mentee.

0.7.5 (2026-10-18)

Changed

  • reports.playbooks and praise.insights return previous: the same counts for the window before the one asked for (null when there is nothing to compare), so a client can show the change since then without a second call.

0.7.4 (2026-10-18)

Added

  • Requests Mello filed outside Shuffl: actions.mine (self:read) lists what Mello filed for the asking person in a connected HR system and where each one stands (status submitted, approved, declined, cancelled, failed or unknown, with statusLabel, provider, providerName, details such as the time-off policy and dates, vendorUrl, submittedAt, settledAt and cancellable). Only the person's own; a key with self:read.
  • sync.setWrites (integrations:write) turns a People Sync connection's write switch on or off: off, Mello files nothing there and sends the person's request to HR instead; reads carry on. sync.current connections now return writes (offered, enabled).

0.7.3 (2026-10-18)

Changed

  • Mello's read as figures: pulse.latestRead also returns delta, the change since the question was last asked (change, direction up/down/flat/new, tone good/bad/neutral/watch, text such as ↓ 6 pts; moves under 5 points read neutral), and gap, the lowest and highest published group with the points between them, or null when the gap is under 15 points. Both are null when the result is withheld.

0.7.2 (2026-10-18)

Added

  • What Mello can do: capabilities.sheet returns the rows Mello can answer (kind: 'ask') and do (kind: 'do') for the key's person in this workspace, each with say (what to ask), result, system (Shuffl or the connected system's name) and status (available, needs_connection, needs_setup or coming), plus need when it doesn't work yet. capabilities.unlocks lists what an HR system or document tool adds once connected. capabilities.requestConnection (self:write) asks HR to connect what a needs_connection row needs; administrator keys read the open asks per capability with capabilities.requests (integrations:read) and clear them with capabilities.dismissRequests (integrations:write). Asks carry counts, never names.

0.7.1 (2026-10-18)

Added

  • Celebrations insights: reports.celebrations (reporting.celebrationInsights) returns, for the last 30, 90 or 180 days (days, default 90) and the same period before, celebrations sent (sent.current.total, with people, birthdays, anniversaries and shared with a channel or team), team cards delivered and the notes on them (cards), share answers (consent.share, consent.private, consent.waiting), messages that failed or were skipped (missed) and a weekly series of birthdays and anniversaries. Counts only. Administrator keys with reports:read.

0.7.0 (2026-10-18)

Changed

  • The CLI reads a workspace key from SHUFFL_API_KEY instead of SHUFFL_TOKEN (breaking), matching the SDK's apiKey option. SHUFFL_COMPANY_KEY and SHUFFL_BASE_URL are unchanged. The README, guides, cookbook and API reference use the new name.

0.6.5 (2026-10-18)

Changed

  • Playbook steps before day 1 go by email. playbooks.enrollmentPreview steps return byEmail: true when the step goes to a hire whose Slack isn't ready yet, so it goes by email to their work email until it is. Meet steps and check-ins never go by email.

0.6.4 (2026-10-18)

Added

  • Mentorship insights: reports.mentorship (reporting.mentorshipInsights, days 30, 90 or 180, optional programId) returns current and previous periods with pairs (started, endedEarly, completed) and checkIns (answered, met, asked, finals, helped), now (meeting, paused, suggested, waiting) and weekly pairs and checkIns. Counts only, never goals. Administrator keys with reports:read.
  • Mentorship settings: mentorship.settings.get returns the settings a new program starts with (pairingWeeks, checkInWeeks, mentorCapacity), Shuffl's defaults and updatedAt; mentorship.settings.save changes them (mentorship:write) and returns changed and custom.

Changed

  • mentorship.programs.save takes pairingWeeks, checkInWeeks and mentorCapacity as optional: a new program left without them starts with the workspace's mentorship settings, and an existing one keeps what it has.

0.6.3 (2026-10-18)

Added

  • Automation insights: groups.automationInsights counts group automation runs finished in the last days (30, 90 or 180) against the period before: current and previous with done, skipped, failed and people reached, weekly, byKind, the top five reasons a run was skipped or failed (code, why, outcome, n), runs still scheduled and automations on of total. groupId narrows it. Administrator keys with users:read.

0.6.2 (2026-10-18)

Changed

  • The READMEs list what the SDK client covers, resource by resource, and say how the packages are licensed. Operation descriptions and release notes no longer cite internal tracker numbers.

0.6.1 (2026-10-18)

Added

  • The SDK and CLI name their release on every request in an x-shuffl-client header (shuffl-sdk/0.6.1, and for the CLI shuffl-cli/0.6.1 shuffl-sdk/0.6.1), so Shuffl can count requests by client and release. new Shuffl() takes an optional client, such as billing-sync/1.2.0, which goes in front; Shuffl never stores that part. No operation changed.

0.6.0 (2026-10-18)

Changed

  • One client for every key (breaking): new Shuffl({ apiKey }) replaces createShuffl and createShufflCompany, which are removed. A workspace key (shuffl_api_) calls the workspace methods at the top level (shuffl.users.list()); a company key (shuffl_company_) calls the company methods under shuffl.company (shuffl.company.members.list()). The client reads the key's prefix and refuses the other kind's methods with UNAUTHORIZED before sending a request. token is now apiKey (a string or a function that returns one), and baseUrl is optional, defaulting to production. The CLI and HTTP API are unchanged.

0.5.12 (2026-10-18)

Added

  • Automation runs, a page at a time: groups.automationRuns lists every group automation run in the workspace newest first, 50 at a time, each with personId, name, groupId, groupName, kind, trigger, outcome, why, at and dueAt. next is the cursor for the next page (null on the last); counts gives every run by outcome (scheduled, done, skipped, failed). outcome and groupId narrow it. Administrator keys with users:read.

0.5.11 (2026-10-18)

Changed

  • Leaving playbooks start on their own: groups.setPlaybookAutoStart now takes a playbook counted from each person's last day (dayZero: 'last_day') as well as one counted from each start date, and playbooks.savePlaybookProgram accepts autoStart on one. When People Sync or People gives someone a last day ahead, they start it within ten minutes, with steps waiting for approval; someone removed is not added back for that last day. groups.allAutomations playbookStarts return dayZero (start_date or last_day).

0.5.10 (2026-10-18)

Added

  • Pulse group results over time: pulse.groupTrends (pulse:read, days 30, 90 or 180) returns each group's published, frozen totals period by period (unit week, fortnight or month, with periods), for everyone and every dimensions row (department, role, tenure, group). Each row's series has one entry per metric (favourable, enps or a driver) with points (value, null when withheld; seen), latest and change since the first published point. eNPS points follow enpsPeriods, the last eight eNPS questions.

0.5.9 (2026-10-18)

Added

  • Playbook form steps: a written step in playbooks.saveProgram can be kind: 'form', going to the hire (recipient: 'hire', no to-dos) with formFields, any of preferredName, pronouns, bio, birthday and photo. The hire answers with playbooks.answerForm (stepId, plus preferredName, pronouns, bio and birthday { month, day } or null); answers write to their profile and Celebrations birthday under their own privacy settings, and the step records only when it was answered. playbooks.mine steps return form (fields, answeredAt) and the run returns formValues. Profiles take and return preferredName.

0.5.8 (2026-10-18)

Added

  • Slack channel automations: groups.setAutomation takes kind slack_invite (add each person to a channel) and slack_post (post that they joined, with an optional config.note; joins only). config.channelId must be a channel Shuffl is in: the API reads it back from Slack and saves config.channelName itself. Automations return the channel as target (#name). The Slack call runs from a queue after the run is written; a refusal turns the run failed with Slack's reason as code, such as not_in_channel, and someone with no linked Slack account is skipped with no_slack.

0.5.7 (2026-10-18)

Added

  • Mentorship programs. Administrators (mentorship:read, mentorship:write): mentorship.programs.list and mentorship.programs.get (programId: the program with members, each with role mentor or mentee, topics, status and open pairs, and pairs with mentor, mentee, reasons, status, dates, checkIns counts and final answers; never goals). mentorship.programs.save (name, description, groupId or null for everyone, pairingWeeks 4 to 52, checkInWeeks 1 to 8, mentorCapacity 1 to 5) and mentorship.programs.setStatus (active, paused or archived, which ends open pairs). mentorship.pairs.suggest suggests one mentor for every waiting mentee, never in their reporting line; mentorship.pairs.decide (pairId, decision approve or skip) starts a pair and introduces both people; mentorship.pairs.end ends one early; mentorship.members.setStatus takes someone off a program (removed) or puts them back. Everyone (self:read, self:write): mentorship.mine lists the programs open to the key's person and their pairings with goals and checkIns; mentorship.join (programId, role, topics) and mentorship.leave; mentorship.pairs.setMine (pairId, status active, paused or ended); mentorship.goals.save and mentorship.goals.remove for the mentee's goals (up to 5); mentorship.checkIns.answer (checkInId, answer helped, met or not_yet). Notification kind mentorship. badges.list includes the automatic Mentor badge for finishing a pairing as the mentor.

Changed

  • home.places can return mentorship when a mentorship program is running or a check-in waits for the person.

0.5.6 (2026-10-18)

Added

  • More group automations: groups.setAutomation takes kind ask_pulse (config.questionId), give_badge (config.badgeId), add_to_group and remove_from_group (config.targetGroupId, a Shuffl list) and tell_person (config.personId, optional config.note), and delayDays (0 to 365) to run that many days after the join or leave. Automations return delayDays, when and target for the new kinds; runs can be scheduled with a dueAt, and groups.allAutomations totals add scheduled. A run that comes due after the person moved back is skipped with code moved_back. groups.automationChoices lists the Pulse questions (id, text, retired), badges and groups an automation can use. Pulse questions an automation asks gather in a send of its own that stays open four weeks and closes a week later, under the reporting floor.

0.5.5 (2026-10-18)

Added

  • Playbook meet steps: a written step in playbooks.saveProgram can be kind: 'meet', going to the hire (recipient: 'hire', no to-dos) with meet set to manager, skip_level (their manager's manager), person (with personId) or teammates (with meetCount, 1 to 5: people with the same manager, longest here first). Who they meet is resolved from People when the steps are reviewed and approved: playbooks.enrollmentPreview and playbooks.previewAs steps return meets (names; empty when People has nobody, which skips the step at approval). The step sends one Slack group message with a card for each person and Pick a time. Calendar targets take kind: 'playbook_meet' with id <enrollment id>.<step id>, and bookings return from (person, group, playbook or playbook_meet). playbooks.mine returns met, the people meet steps introduced the hire to.

0.5.4 (2026-10-17)

Added

  • Playbook tracks: written steps in playbooks.saveProgram take onlyFor and notFor (up to 5 group ids each, from groups.list; empty is everyone). A step only for groups goes to people in any of them, and a step not for a group never goes to its people. Groups are checked against People when the steps are reviewed and at approval: playbooks.enrollmentPreview steps return track (why this person doesn't get it, such as Only for Engineering, or null), a People change before approval fails playbooks.approve until the steps are reviewed again, and approved steps a track leaves out are skipped with no to-dos. playbooks.program returns tracks (each group the steps name, with id, name, kind, department, rules in words or null, only and not step counts and hires on the playbook now in it). playbooks.previewAs (programId, personId) returns the steps one person would get, without enrolling them: dayZero, person, steps (each with ref, title, kind, offsetDays, dueAt, recipient, track and skipped, why they wouldn't get it), skipped and tracked.

0.5.3 (2026-10-17)

Added

  • Connections for employees: network.introductions returns the key's own programs (each Connections program that introduces them, with id, name, nextAt, null while paused, and breakUntil), past (their latest introductions, each with id, at, program and with: the other people, id, name, title, photoUrl and slackUserId) and total. Nothing about other people's introductions or matches not yet sent. home.places can include connections.

0.5.2 (2026-10-17)

Added

  • One list of join and leave rules: groups.allAutomations also returns playbookStarts (each playbook that starts on each new hire's start date: playbook with id, name and status, group or null for everyone, state active or paused, runs, runs30 and lastRunAt) and programRosters (each Connections program whose people are a group: program, group and state). groups.setPlaybookAutoStart (programId, state active, paused or off, optional groupId, null for everyone) turns a playbook's start-date rule on, pauses it keeping its group, or removes it. Playbooks return playbook.autoStartPaused; a paused playbook starts nobody until it is turned back on.

0.5.1 (2026-10-17)

Added

  • Playbook Hires view: playbooks.program returns hires (active, onTime percent of to-dos done by a day after their day or null, overdue, askedForHelp) and each active row's progress (day from day 0, done, total, next step title and at, overdue to-dos grouped by owner with ownerId, ownerName, role hire, manager, buddy or other, count, since and nudgedAt, unconfirmed read-and-confirm pages and help). playbooks.nudge (enrollmentId, ownerPersonId) sends that person one Slack reminder with their overdue to-dos for the hire and returns status sent, recent (already nudged today), nothing_overdue, off, no_slack or failed.

0.5.0 (2026-10-17)

- playbooks: answerBuddyAsk, answerBuddyFollowUp, answerCheckIn, answerFirstDaysCheckIn, approve, askBuddy, assignBuddy, buddyCandidates, buddyFollowUps, buddyProgram, buddySuggestions, candidates, completeTodo, draftPlan, enroll, enrollmentPreview, firstDaysCheckIns, firstDaysResults, mine, person, plans, previewEnrollment, program, remove, respondBuddy, retry, run, savePlan, saveProgram, setBuddyVolunteer, setPlanGoal, sharePlan, update, volunteerAsBuddy - onboarding: answerBuddyAsk, answerCheckIn, approve, askBuddy, assignBuddy, buddySuggestions, candidates, completeTodo, mine, person, remove, respondBuddy, retry, update (removed)

Breaking

  • Playbooks everywhere. The onboarding.* operations are now playbooks.*, with the same inputs and outputs. onboarding.journey, a person's run through a playbook, is playbooks.run, and reports.onboarding is reports.playbooks. The onboarding:read and onboarding:write scopes are playbooks:read and playbooks:write; existing keys and connections keep their access under the new names. Webhook event types onboarding.* are playbooks.* (such as playbooks.enrolled and playbooks.step.sent), and subscribed endpoints were moved over. Values that said onboarding or journey say playbook: program and draft kind playbook, the playbook config on playbooks.saveProgram, playbooks.program and programs.*, group automation and Culture nudge kind start_playbook, reminder kind playbook_todo, notification kind playbook, citation kind playbook, person activity kinds playbook_started and playbook_completed, playbookMessagesSent, and the playbooks list on playbooks.run.
  • Departments are groups. Every department is now a group (same id) marked department in groups.*, and a person is in one department at most. units.save and units.archive are gone: create a department with groups.save (kind list, department true, people in personIds), rename it with groups.save and remove it with groups.remove; departments are no longer archived. units.list takes no archived and returns id, name and members for each department. groups.list, groups.get and the other group reads return department. A department group is never onProfile or the HR team and can't be a rules group. users.save still sets a person's department with departmentId (a department group's id), and users.page's departmentId filter reads department groups. Program unitIds, knowledge audience units and group rules on department keep working with the same ids. exports.team no longer returns organizationUnits or unitMemberships: departments are in peopleGroups and peopleGroupMembers with department true, and an older export that carries them still imports. The directory.unit.created, directory.unit.updated and directory.unit.archived webhook events are gone, since nothing sends them; read departments with units.list or groups.list. An endpoint subscribed to them keeps its other events, and saving it drops them.
  • Teams are groups. Every team is now a group (same id) in groups.*, and units.* covers departments only: units.list and units.save no longer return kind, hrTeam or slackUserGroupId, and units.save takes no kind. Groups return source (shuffl, slack or directory: synced groups have read-only members), onProfile (shown on profiles and the org chart, as teams were) and hrTeam (the group that answers HR requests); groups.save takes onProfile, and refuses member or rule changes on a synced group. users.details returns department and groups instead of units, and users.save takes groupIds instead of teamIds. users.page filters by groupId instead of directoryTeamId; users.filterOptions and programs.options return units of kind department or group. profiles.get and network.orgChart return groups instead of teams. Pulse results no longer split by team: pulse.insights and pulse.questionDetail drop the team dimension, and former team results are under group. digest.culture returns focus.kind department or group. A group rule team is X becomes segment (In group). exports.team returns peopleGroups and peopleGroupMembers.
  • Pulse questions go to a group, not an audience. pulse.addQuestion takes groupId (one of the workspace's groups, or null for everyone) instead of audience, and pulse.setQuestionGroup (questionId, groupId) replaces pulse.setQuestionAudience. pulse.audienceOptions is gone: pick from groups.list. pulse.questions, pulse.questionDetail, pulse.actions, pulse.action and pulse.insights return groupId and groupLabel where they returned audience and audienceLabel. eNPS still goes to everyone.

Added

  • users.page rows return directory: jobTitle from the directory for every key, and startDate (a calendar date) for administrator keys only, null for everyone else.
  • New hire 30/60/90 plans: playbooks.plans lists the plans for the new hires the key's person manages (asManager: each new hire playbook episode with hire, startDate, programName and plan or null) and their own plan once shared (asHire). playbooks.draftPlan has Mello draft three goals per stage (draftedBy ai, or rule without a model); playbooks.savePlan (enrollmentId, expectedRevision, goals with stage 30, 60 or 90 and text, at most 5 per stage) edits them; playbooks.sharePlan shows the plan to the hire; playbooks.setPlanGoal (goalId, done) ticks a goal off, for the manager or the hire. Only the hire and their manager in People change a plan. playbooks.program rows return plan (state none, draft or shared, done, total, and goals with stage, text and done for HR to read) on new hire playbooks. Mello now drafts each new hire's plan by itself when they join a playbook counted from their start date, and plans return autoDrafted.
  • Buddy program health: playbooks.buddyCandidates (personId) suggests up to five buddies for a new hire, never anyone in their reporting line, volunteers first, each with reasons, volunteer and load (active, total). playbooks.volunteerAsBuddy (volunteer) puts the key's person on the buddy volunteer list or takes them off; playbooks.setBuddyVolunteer (personId, status volunteer, removed or none) is HR's version, and only HR undoes removed. playbooks.buddyProgram lists volunteers and recent buddies with status, load, hiresAnswered, hiresMet, hiresHelped and neverMet. playbooks.buddyFollowUps and playbooks.answerBuddyFollowUp (feedbackId, answer helped, met or never) are the "did you meet?" question sent to the hire and buddy on the playbook's buddyFollowUpOffsetDays (default 30). Onboarding playbooks also take buddyTopics, the list sent to the buddy with the invitation.
  • Add people by department or community: playbooks.previewEnrollment and playbooks.enroll take departmentId (everyone in a department) or communityId (everyone who shows a community on their profile) beside groupId; one at a time, and people already on the playbook are left out.
  • Playbooks that start automatically: playbooks.saveProgram takes, and playbooks.program and programs.* return, playbook.autoStart (default false) and playbook.autoStartGroupId (a group, or null for everyone). Only a playbook whose dayZero is start_date can start automatically. Once it is on, everyone People gives a start date ahead (People Sync or an edit) starts it within ten minutes, with steps waiting for approval as playbooks.enroll leaves them. Each person starts it once per start date: someone removed is not added back, and a new start date is a new episode.
  • Every group automation in one list: groups.allAutomations returns each automation of the workspace with its group (id, name, kind, members) beside the fields groups.automations returns, totals (active, paused, groups, and done30, skipped30, failed30 runs in the last 30 days) and the latest 20 runs across groups with groupName. targetId keeps only the automations that start that playbook or program or invite to that community. groups.list and groups.get return automations, how many of the group's automations are on.
  • Read and confirm in playbooks: a playbook step can be kind acknowledge in playbooks.saveProgram, naming one published Knowledge page in resources and going to the hire. Once it goes out, the person confirms the page in the app as for a policy confirmation; playbooks.program returns each such step's answeredAt and acknowledgedVersionId, and playbook.journey returns page and confirmedAt on its steps.
  • Praise in the network and badges: network.mine suggestions carry praised (true when the two people thanked each other, or one thanked the other, in public praise in the last year) and list the reason first (Praised you, You praised them or You praised each other); it stays a suggestion until both say they know each other. badges.list includes three automatic badges for being thanked in public praise: First thanks, Thanked across teams (from three departments) and Lives our values (five thanks for one value).
  • Connections from communities: programs.create and programs.update take communityIds (1 to 20 of the workspace's communities) so a program's people come from those communities instead of everyone in the Slack channel or a group; a program uses one of the three, and choosing a group or communities in an update replaces the other. Only members who show the community on their profile take part, read again before each round; introductions are still posted in the program's channel. match.unitKind takes community, so cross-unit mixes people from different communities and within-unit keeps each group inside one (within a program's own communities when it has them). programs.get and programs.list return communityNames, programs.options returns communities (id, name, memberCount of members who show it) and programs.communities lists the same.
  • How people like to be thanked: praise.setRecognition (recognition: public or private) sets the key's own choice; choosing private hides praise they already received from their profile and the feed, and returns how many were hidden. praise.mine returns recognition and notes (received and given private notes, each with id, giver, recipient, text, values and sentAt). praise.send takes privately (send each person a private note instead of posting) and sends a private note to anyone who prefers one; it returns posted, privateNotes, notSent (names Slack refused a note to) and a praiseId that is null when nothing was posted. praise.insights returns teams and locations beside departments, each row with low when under coverageLow percent were recognized, and counts private notes as recognition. praise.settings and praise.saveSettings carry managerNudges.
  • SCIM groups: a group's source can be scim, a synced group whose members follow the identity provider. sync.groups and sync.setGroup take a SCIM connection's id too (from sync.current, provider scim, connection.source scim) when called by a signed-in company administrator: imported brings the group into every workspace of the company, onProfile applies to this workspace, and syncing is always false because members arrive at once; like other synced groups, its members are read-only in groups.save and users.save.
  • Outgoing webhooks: webhooks.list, webhooks.get, webhooks.catalog, webhooks.create, webhooks.update, webhooks.delete, webhooks.rotateSecret, webhooks.sendTest, webhooks.deliveries.list, webhooks.deliveries.get, webhooks.deliveries.replay and webhooks.deliveries.replayFailed, under the new webhooks:read and webhooks:write scopes. create takes a public https:// url, an optional description and events (catalog types; each group needs its read scope, such as knowledge:read for knowledge.* and hr:read for hr.*), and returns the endpoint, its signing secret (whsec_…, shown only here and from rotateSecret) and the testDeliveryId of the webhook.test it queues. rotateSecret takes keepOldFor (now, 1h, 24h or 7d); both secrets sign until then. Deliveries follow Standard Webhooks (webhook-id, webhook-timestamp, webhook-signature) with retries for a little over a day. The SDK exports verifyWebhook({ body, headers, secret }), signWebhook, webhookEventCatalog, webhookEventTypes and the WebhookEvent type from @shuffl/sdk, and the catalog from @shuffl/api-contracts/webhooks.
  • Warm introductions: network.requestIntro (personId, viaId) asks someone you and that person both know to introduce you. Shuffl sends them a Slack DM with Introduce and Not this time; Introduce starts a group DM with the three of you. It returns id, created (false when the same request was already waiting) and state (asked). The person asked must have a tie to both of you that you can see, and you can have 3 requests waiting at once. network.mine returns, on each suggestion, introVia (the first person in common Shuffl can ask, or null) and intro (your latest request about them: state asked, introduced or not_this_time, with viaId). A decline only ever reads as not_this_time. reminders.settings, reminders.saveSetting, reminders.mine and reminders.saveMine cover a new kind, network ("Do you know this person?", choices once_a_week and once_a_month, off by default).
  • Choosing synced groups: sync.groups (directory.providerGroups, connectionId) lists every group a People sync connection or the Slack workspace (its connection id is the Slack team id) offers, each with id, name, memberCount (people in it at the source), imported, groupId (the group in Shuffl, when brought in), onProfile, listed (seen by the latest sync) and seenAt, plus the connection (id, label, provider, source). sync.setGroup (directory.setProviderGroup: connectionId, id, imported and/or onProfile) brings a group in, takes it out or shows it on profiles, and returns groupId, imported and syncing (a sync started so its members arrive). New groups from a source no longer become groups by themselves: a sync lists them and only the ones brought in follow the source. Taken out, a group stays a Shuffl list with its members. sync.current connections return groups (listed, imported).
  • Group stats: groups.glance (id) returns a group at a glance in the same shape as users.glance, counted over the group's current members: headcount, enough (5 people or more; below that the splits are empty), hiredThisYear, averageTenureYears, tenure, departments, timezones, me (where the key's person sits by start date, when they are in it) and topics (what its people are asked about). leftThisYear is always null. Any key reads groups shown on profiles; an owner or administrator key reads any group. A group the key can't see is NOT_FOUND.
  • digest.culture returns the morning Culture page's figures: week (people thanked, introductions and playbooks finished in the last seven days), playbooks (the four busiest active playbooks, each with id, name, leaving, active and up to four people with enrollmentId, name, photoUrl, day, progressPct, flag: help, no_buddy or late, and late), help (new hires who asked for help at a check-in in the last 14 days), wins (finished playbooks this week and shared work anniversaries in the next seven days), focus.company.previous (the company's thankedPct, metPct and pulse over the 90 days before) and each outcome's short step.
  • Groups for everyone: groups.directory lists the groups shown on profiles to any key in the workspace, the key's own groups first, each with id, name, description, source, hrTeam, memberCount, mine and up to five faces (id, name, title, photoUrl). groups.directoryGroup (id) reads one with every member the same way; a group not shown on profiles is NOT_FOUND. People whose employment ended are left out of both.
  • users.glance returns undated, how many people in the headcount have no start date, and leftThisYear, how many were marked as left in the last year: a number for an owner or administrator key, null for anyone else.
  • celebrations: thisWeek lists who was celebrated in a channel in the last seven days (days, and people, each with personId, name, eventType: birthday or anniversary, years and sentAt). Celebrations sent privately or to a person's own team are left out.
  • Automations on a group: groups.setAutomation adds or changes what happens when someone joins or leaves a group (groupId, trigger: entered or left, kind: send_message, start_onboarding, invite_community, add_to_program, tell_hr or tell_manager, and a config for the kind: the message's subject, body, action and channel; a programId; a communityId; or a note). A new automation starts paused; groups.setAutomationState (id, state: paused or active) turns it on or off, groups.removeAutomation (id) drops it with its runs, and groups.automations (groupId) lists a group's automations with each one's summary, state, runs and lastRunAt, and its last 50 runs (personId, name, trigger, outcome: done, skipped or failed, and why a run did nothing). Runs happen from the groups refresh, once per person and entry; personActivity.personActivity returns them as group_automation events.
  • Message a group: groups.prepareMessage writes a draft to everyone in a group (groupId, subject, body as paragraphs, optional action with label and a path starting with /app, and channel: preferred, slack or email) and returns it with preview (how it reads to its first recipient, with {{first_name}}, {{manager}} and {{company}} filled in) and reach (recipients, reachable, alreadyToday, unreachable). groups.sendMessage (id, requestKey) queues it once per request key on each person's chosen channel, leaving out anyone HR already messaged that day, and returns queued and skipped; the same key replays the result. groups.messages (groupId) lists a group's drafts and sends, groups.message (id) reads one with its preview and reach, groups.discardMessage (id) drops a draft, and groups.export (id) returns the members as csv with a filename. People get the message under the new hr_message notification kind in notifications.preferences, which offers Slack and email and cannot be fully turned off; a Slack thread reply to one becomes an HR request.
  • A Connections program's people can come from a group: programs.create and programs.update take groupId (null or omitted keeps the Slack channel roster), programs.get and programs.list return groupId and groupName, programs.options returns groups to pick from, and programs.syncRoster reads the group's members when one is set. Joining or leaving the channel no longer changes who takes part in such a program; the channel stays where introductions are posted.
  • playbooks.previewEnrollment and playbooks.enroll take groupId: everyone in that group who is not on the journey yet is added after rows, which may now be empty. The preview returns the expanded rows and its fingerprint covers them.
  • groups: list, get, members, options, searchPeople, suggestions, preview, save, refresh, remove. A group is a live set of people in the workspace, kept by rules on People attributes (re-evaluated every ten minutes and on save) or a list picked by name; suggestions lists the starter groups not made yet and preview counts who a set of rules would hold today.
  • knowledge.templates: draft has Mello research a policy template and write the whole page. Send the template id, title, body (the template text, prefilled or not), its checks, and optional notes and website. It returns title, body, choices (each value Mello chose, with its topic, value, basis: company, law or typical, and the source link the web search returned, if any), sources, placeholders (how many are left) and researched (whether the web search ran). Nothing is saved.
  • knowledge.templates: facts returns what Shuffl knows that policy templates ask for: companyName, hrContact (who answers HR requests), hrRequests (whether people can send one), countries (from the directory's time zones, most people first) and holidaysTitle (the published holidays page). The app fills a new template's placeholders with them.
  • knowledge.handbook: export returns the pages published to everyone as one handbook: teamName, generatedAt, pages (each with title, effectiveAt, version and its Markdown body), leftOut (how many published pages are for particular groups or admins only) and the whole handbook as markdown. Each call is recorded as a download.
  • knowledge.acknowledgements: status, request, remind, close, mine. HR asks the people who can read a published page to confirm they read it: request asks the page's audience to confirm its published version (and messages them unless notify is false), remind messages the people who haven't confirmed, close stops asking, and status lists who is asked and who confirmed which version. mine lists the pages the key's person is asked to confirm. Confirming itself happens only in the app.
  • Notification preferences cover a new kind, policy_acknowledgement: the message asking someone to read and confirm a Knowledge page.
  • digest: culture lists the Culture page's recommendations in Mello's order, each with its area (praise, connections, onboarding or pulse) and rank, and outcomes: what happened after each recommendation acted on in the last 60 days. It also returns focus: each department (or team, in a smaller company) of 7 or more people with its share thanked, share introduced to another team, new hires without a buddy and Pulse score beside the company's, the areas where it is behind, and introductions between each pair of groups. Each group also carries its weakest Pulse driver (weakDriver), responsePct, joined, left, needHelp, missedCheckIns and previous figures for the 90 days before, and focus.praise counts praise between groups.

Changed

  • Badge offers when a project or event channel goes quiet: badges.settings returns and badges.saveSettings takes channelOffers (default true). Once a day Shuffl looks at the channels it is in whose names mark a project, launch or event and offers the channel's maker a badge for everyone who posted, once per channel; such offers have source channel.
  • Celebration send days: celebrations.save and celebrations.preview take sendDays (ISO weekdays, 1 = Monday; Monday to Friday when left out) and offDayShift (before or after: where a birthday or anniversary on another day goes), and celebrations.program returns both for each celebration. celebrations.preview returns the sample's sendDate and shifted, and celebrations.review rows carry sendDate, the local day each one goes out.
  • Journeys are now called playbooks. Operation descriptions, error messages and the app's links say playbook and point at /app/playbooks and /app/playbooks/all; the old /journeys addresses redirect there. Operation names and fields followed in a later release.
  • Slack user groups become synced groups with source slack, kept in step with Slack's members. The Slack import also fills jobTitle, timezone, startDate and managerId in directory.directoryPerson from Slack profiles for people no HR system manages.
  • Pulse results HR can share: pulse.program returns and pulse.saveProgram takes shareResults (default false). When it is on, pulse.asked returns result on each closed question asked to everyone whose reporting floor was met (unit: favourable or eNPS, value, respondents); otherwise result is null.
  • Journeys: onboarding is the first kind of journey. playbooks.saveProgram takes, and playbooks.program and programs.* return, playbook.dayZero (start_date, joined or date: what each person's days count from), playbook.dayZeroDate (the one date when dayZero is date), playbook.buddy and playbook.helpCheckIn (whether the buddy messages and the help check-in are part of the journey; both default to true). A joined journey has no steps before day 0. playbooks.enroll and playbooks.previewEnrollment fill a missing startDate from the journey's day 0. playbook.journey takes an optional enrollmentId and returns enrollmentId, dayZero, buddyOn and journeys (each journey the person is on, with current). playbook.personOnboarding returns buddyOn per enrollment.
  • Catch-up for people who join a journey after day 0: playbooks.saveProgram takes, and playbooks.program and programs.* return, playbook.catchUp (skip, the default, bundle or shift). playbooks.enroll takes an optional catchUp for that batch and returns catchUp and late, how many were added after day 0. playbooks.previewEnrollment returns missed per row and catchUp (default, late and sample, one person's steps under each choice). playbooks.enrollmentPreview returns joinedOn and catchUp per step (planned, today, skipped or bundled). Steps can have the status skipped and the kind catch_up, the one What you missed message.
  • Check-ins on any day with a journey's own questions: a journey step of kind checkpoint can have checkpoint: 'custom' with questions (1 to 6, each with an id, text and kind: scale with a scale of agree_5, rating_5 or yes_no, or open), on any day and as often as the journey likes, in playbooks.saveProgram, playbooks.program and programs.*. playbooks.firstDaysCheckIns returns them with checkpoint set to step:<journey id>:<step id>, plus intro, note and journey on every check-in; playbooks.answerFirstDaysCheckIn takes that checkpoint and answers the step's questions. playbooks.firstDaysResults returns journeys: each journey's own check-ins (programId, journey, stepKey, title, offsetDays, dayZero, sent, answered, published and questions), combined only within that step and shown above the reporting floor like the built-in ones. playbook.journey returns kind per checkpoint (day_30, day_60, day_90, day_365 or custom) and checkpoint as the check-in's subject.
  • Leaving: directory.saveDirectoryPerson takes, and directory.directoryPerson returns, lastDay (the person's last day; null clears it, left out keeps it) and lastDayAnnounced (default false). Shuffl never takes or stores a reason. Until a last day is announced, directory.directoryPerson returns lastDay as null to anyone but owners, admins and the person's manager. A journey's playbook.dayZero can be last_day: each person's days count from their last day in People, with steps up to 60 days before and after, and no buddy. Until the leaving is announced only steps to the manager and HR go; the others wait with status waiting and errorCode until_announced. A changed last day sends the run's unsent steps back for approval at the new dates, and a cleared one ends the run with removalReason leaving_cancelled. playbooks.previewEnrollment reports missing_last_day for someone without one. Ending someone's employment or access no longer ends their leaving journey; only the steps to them stop.
  • praise.feed returns values: on the first page, the five values praised most in the last 30 days (value, count), counted from the praise the key's person can read. Later pages return an empty list.
  • Pulse results by people group: pulse.insights and pulse.questionDetail return a fifth split, groups.dimensions.group (questionDetail: groups.group), one row per group with the same label, respondents, favourablePct, enps and drivers as departments and teams. pulse.insights also lists every current group with seen: false until a question closes after it was made. A group's figures are withheld under the reporting floor, when the people outside it are under the floor, and when it and any other published total would give fewer than the floor away by subtraction.
  • Praise in private Slack channels: praise.feed and praise.ofPerson include praise from private praise channels the key's person is in now, and praise.mine leaves out private channels they have left. praise.composer returns private per channel and offers private channels only to their members; praise.send refuses a private channel for someone who isn't in it. praise.settings returns membersFresh and membersError per channel.
  • Charts on the employee People page: users.glance returns monthly, the last twelve months of headcount and people who joined (empty below five people).
  • Onboarding to-do reminders: reminders.settings, reminders.saveSetting, reminders.mine and reminders.saveMine cover a third kind, onboarding_todo, with the choices one_day_late and three_days_late. It is on (one_day_late) unless a team turns it off.
  • Mello answers from the asker's onboarding journey: a citation's kind can be onboarding in assistant.history, linking to Your onboarding. knowledge.search, knowledge.context and manager.current share the citation shape but never return it.
  • reports.onboarding returns hires.withBuddy, the hires in onboarding now who have a buddy. digest.actOnNudge and digest.dismissNudge accept from: 'culture' for nudges acted on from the Culture page. Culture nudges have six more kinds: praise_low, pulse_low, start_praise, start_pulse, start_onboarding and start_cross_team.

0.4.0 (2026-10-12)

The company API joins the SDK, the CLI and OpenAPI. It takes a company key (shuffl_company_) from Company settings → API keys, never a workspace key, so it has its own client and commands.

Breaking

  • GET /api/v1/company/members.list is paginated: it takes limit (1 to 100, 25 by default) and cursor, and returns { items, nextCursor } instead of an array of every member. Scripts that call it over HTTP read items and follow nextCursor.
  • The first 90 days' check-ins are onboarding journey steps (kind: 'checkpoint' with checkpoint of day_30, day_60, day_90 or day_365). reminders.settings, reminders.saveSetting, reminders.mine and reminders.saveMine now cover only praise and pulse: the manager_check_in and new_hire_check_in kinds and their choices are gone. onboarding.firstDaysResults no longer returns manager, and onboarding.journey no longer returns managerCheckIns.

Added

9 operations, by resource:

  • company: current, details, rename
  • company.emailDomains: list
  • company.members: list, remove
  • company.slack: list
  • company.workspaces: list, setDefault
  • onboarding: completeTodo checks off (or reopens) one of your own onboarding to-dos.

SDK, CLI and OpenAPI

  • SDK: createShufflCompany({ baseUrl, token }) returns a typed client for these operations, such as company.members.list({ limit: 100 }). It calls the REST paths under /api/v1/company and throws ORPCError like createShuffl.
  • CLI: shuffl company commands, with shuffl login --company --token-stdin and shuffl logout --company, or SHUFFL_COMPANY_KEY in the environment. The company key is saved in company.json, apart from the workspace key.
  • OpenAPI: the operations are under /company, with the companyKey security scheme and x-shuffl-credential: company.

Changed

  • Company API responses return exactly the published fields: company.details no longer includes internal, and company.slack.list sends revokedAt as an ISO time.
  • Company API errors include status and defined: false, like workspace API errors.
  • Onboarding journeys: onboarding.saveProgram, onboarding.program and programs.* carry onboarding.steps, the steps HR writes (message, to-do or check-in, day offset, recipient, Knowledge, link and community resources, to-dos). onboarding.enrollmentPreview returns each step's ref, title, recipient and to-dos; onboarding.program returns stepKey and title per step; onboarding.journey returns todos, gettingReady and resources.
  • reports.people returns history: headcount, joins and people marked as left for each of the last 12 months, plus today's departments and tenure.
  • exports.team and reports.overview return each program's onboarding.steps too; credentials.api.create, credentials.api.list and permissions.list include the onboarding.completeTodo permission.
  • reports.onboarding returns messages.weekly (sent and on time per week); praise.insights returns givers and recognized per week.

0.3.0 (2026-10-12)

Breaking: two fields were removed and one object was reshaped, so this is a minor release. Upgrade the SDK and CLI together.

Breaking

  • teams.setup: slack.connected and slack.status are replaced by slack.state, slack.live and slack.reason.
  • celebrations.preview no longer returns fingerprint, and celebrations.save no longer takes previewFingerprint.

Added

7 operations, by resource:

  • celebrations: saveAnniversaryDate, startDates
  • home: places
  • hr: mine
  • onboarding: journey
  • teams: slackConnection
  • users: glance

Changed

  • Schedules take days (1 to 7, Monday first) to pick days of the week: program schedules in programs.* and reports.overview, reminders.saveSetting and reminders.settings. pulse.program and pulse.saveProgram add sendEvery, sendUnit, sendStart and sendMonthWeek.
  • Notification kinds add check_in and getting_started (notifications.preferences, notifications.save).
  • users.save takes originalStartDate; exports.team returns it, and celebrations.preferences returns startDate.
  • communities.members returns joinedAt; praise.settings returns slack; sync.current returns slack per connection; digest.preview returns trend and a ratio per section; operations.activity always returns summary.
  • profiles.whoKnows takes from; support.create takes guides; praise.send accepts more from values.
  • credentials.api.create, credentials.api.list and permissions.list include the new operations' permissions.

0.2.1 (2026-10-03)

No operation changes. shuffl --help and the OpenAPI summaries now describe all 303 operations in words. In 0.2.0, 133 of them showed only their operation id, such as access.get.

0.2.0 (2026-10-03)

Breaking: while the major version is 0, a minor release may rename or remove operations. Upgrade the SDK and CLI together.

Renamed

  • workspaces.* is now teams.*: current, setup, status, initialize, saveAgentSetup, resendSlackWelcome, slackJoinAccess, saveSlackJoinAccess, slackProfileLink, saveSlackProfileLink, syncSlackProfileLinks. GET /api/v1/workspace is now GET /api/v1/team, and the /manage/workspaces/... paths are now /manage/teams/....
  • exports.workspace is now exports.team.

Removed

  • billing.*: company billing moved to Company settings, and a team key never gains company scope.
  • provisioning.current and provisioning.configure: SCIM connections are created in the browser, because creating one issues the identity provider's secret.

Added

97 operations, by resource:

  • badges: generatePicture, holders, saveSettings, settings, uploadPicture
  • celebrations: card, cards, removeCardNote, signCard
  • communities: channelSuggestions, createCapabilities, createSlackChannel, fromChannels, generateCover, invite, revokeInvitation, uploadCover
  • digest: actOnNudge, dismissNudge, nudge, nudges, preview, saveSettings, settings
  • exports: team
  • getStarted: celebrate, celebration, dismiss, draftIntro, get, intro, wizard
  • home: preferences, react, story
  • hr: categories, rebuildCategories, saveCategories
  • invitations: candidates, createMany, inviteDirectory
  • knowledge: sources.write
  • onboarding: answerBuddyAsk, answerFirstDaysCheckIn, firstDaysCheckIns, firstDaysResults
  • praise: composer, send
  • profiles: whoKnows
  • pulse: actions, answer, audienceOptions, createAction, decideProposal, editProposal, latestRead, mine, proposals, proposeQuestions, questionDetail, requestProposals, setQuestionAudience, skip, updateAction
  • reminders: mine, saveMine, saveSetting, settings
  • reports: melloTrial, melloValue
  • runs: history.get, history.list, stopKnownFailures
  • team: answerMinutes, dismissLaunchPost, launchPost
  • teams: connectionPermissions, current, discardPairHistory, initialize, moveSlackChannels, rename, resendSlackWelcome, saveAgentSetup, saveSlackJoinAccess, saveSlackProfileLink, setup, slackChannels, slackJoinAccess, slackProfileLink, status, syncSlackProfileLinks, uploadPairHistory
  • users: assignManagers, proposeReportingLines, reportingLineProposal, reviewReportingLines

Was this guide helpful?