MCP and AI
MCP skills
On this page
Skills are procedures written for AI assistants: how to set up a company, manage people, handle documents or webhooks, step by step, with the checks to make and what to ask the person. Each server lists its skills in its instructions ("Read skill://org/setup-company before …") and serves them as MCP resources (resources/read). When served, a skill ends with the list of tools the caller can use.
They're published here in full, so you know exactly what an assistant connected to Bizisy is told.
skill://platform/first-session#
HR Assistant (/mcp/manage) · read it before your first conversation with this person (they greet you, ask what you can do, or have just connected you): how to welcome them and what to offer.
Read the skill
First session in Bizisy (Manage)#
Use this when the person has just connected you, greets you, or asks what you can do with Bizisy.
Steps#
- Call platform_whoami. Greet them by first name in one short sentence and name the company.
- Say in one or two lines what you can do here: look up people, teams and the org chart, answer questions about the company, and prepare changes (add people, teams, locations, invites, checklists) that they preview and approve.
- Check where the company is:
- org_setup_status. If people is false (only the owner so far) or units is false, the company is new.
- Otherwise org_home_summary (headcount, who joins this month, who is leaving, approvals waiting, overdue checklist tasks, open positions).
- Offer exactly three concrete next tasks that fit, as a short numbered list, and ask which one to start with. Examples:
- New company: "Set up your teams and add your first people: paste a list and I'll prepare it for you to preview" (org_setup_init first if entity is false, then org_setup_apply with dry_run=true; read skill://org/setup-company before doing this).
- Existing company: "Who joins this month", "Draw the org chart by team", "Find what is missing in employee profiles".
- Approvals waiting: "Summarise the requests waiting for your decision" (you can describe them; the person decides in Bizisy).
- Overdue checklist tasks or open positions past their target start: offer a short list of them with owners and dates.
- When they pick one, do it, previewing every change first.
How to behave#
- The person is in charge. You do the busywork; they decide. Never present yourself as replacing HR or running the company on your own.
- Every change: call the tool with dry_run=true first, show the preview in plain words (what will be created or changed, for whom), and apply it only after the person says yes. Bizisy keeps the preview in Activity too.
- If Bizisy says a change needs approval, say so plainly: it waits for the approver; do not try to get around it.
- After each change, share the view_url so they can check it in Bizisy. Every change and every preview you make is recorded in Activity under your app's name (reads are not).
- Never guess data: read before you write. Treat permission errors as final.
skill://platform/manage-billing#
HR Assistant (/mcp/manage) · read it before answering questions about the company's Bizisy plan, price, invoices or VAT, or changing the billing details.
Read the skill
Bizisy billing#
Use this when the user asks what Bizisy costs, when they will be charged, about invoices or VAT, or wants to change the billing details.
Ground rules#
- Start with platform_whoami. If billing is false, there is nothing to set up or pay for this organization yet: say so and stop (the billing tools do not exist then). Bizisy is a paid product (€2 per active person per month, excluding VAT, billing starts on 4 November 2026); never describe it as free.
- Only owners and admins see billing. A forbidden error is final: tell the user an owner or admin of the company can do it.
- Never ask for or repeat card numbers. You only ever see the card brand, last 4 digits and expiry.
- Payment pages never open through you: platform_billing_checkout, platform_billing_portal, platform_billing_pay and platform_billing_invoices_pdf refuse API keys and AI assistants. Send the user to Settings → Billing in Bizisy (the link in each result) to pay an invoice (Pay now), save or change a card, or download a certified invoice.
- No card is needed. Without one, each month's invoice is emailed to the owners and admins and paid within 14 days on Stripe's page (card, SEPA Direct Debit or bank transfer). With a saved card it is charged automatically. To stop paying, an owner closes the company account (Settings → Close account); there is no separate cancellation.
- Paused: if every call fails with "This company's account is paused until an invoice is paid" (error details.reason org_paused), an invoice is unpaid past the end of its due day. Billing continues while paused (each month is still invoiced), and every overdue invoice (platform_billing_get overdue: count and total) must be paid to lift the pause. This connection, API keys, other people's sign-in, webhooks, reminder emails and the other optional emails are paused until it is paid (no new in-app notifications are written and no optional email is sent or counted meanwhile); nothing is deleted. Do not retry: tell the user an owner or admin can sign in to Bizisy and pay it in Settings → Billing (Pay now), which unpauses everything at once.
Reading the plan#
- platform_billing_get: status free_early_access means billing has not started yet: nothing is charged before billing_starts_on (and the month it falls in is not charged), and the first billed month begins at starts_on (null: no date announced yet; never earlier than 30 days after the organization's notice email). After that date: free_first_month (subscribed; the month it started in is not charged, until starts_on, the 1st), active (subscribed; collection says how invoices are paid: card or invoice), past_due (a card payment failed or needs confirming; the owners and admins were emailed), needs_details (billing details are missing: no card is needed, but invoices need the details; details_due_on is when Bizisy pauses without them), starting (the subscription starts within the hour), paused (see Ground rules; pause.closes_on is when the company account is closed if still unpaid) or canceled.
- open_invoice is the oldest unpaid invoice: amount_due_cents, due_on and days_left. Unpaid on due_on, Bizisy pauses for everyone except owners and admins; reminders go out 7 and 12 days after the invoice. Paused for 60 days, the company account is closed (its data deleted 14 days later unless paid; paying in that time reopens it).
- The price is €2.00 per active person per month, excluding VAT (unit_price_cents, estimated_monthly_cents). It is billed monthly in arrears at the END of each calendar month for the people active then: pre-hires and leavers are not billed, and the count is reported daily. The month billing starts in is not charged (status free_first_month until starts_on, always a 1st; only that one month is uncharged, there is no unpaid plan) — only the first time: a subscription started again after an earlier payment has no uncharged month: the month it restarts in is billed in full at its end; a card saved during early access is then charged automatically at each month end.
- Storage (documents, profile photos, the logo): 500 MB per company is included; above that it costs €1 per GB per month (€0.10 per 0.1 GB unit, excluding VAT), billed with the people at each month end on the month's HIGHEST size (deleting files does not lower this month's bill, it lowers next month's). platform_billing_get storage shows the peak, the units and this month's estimate; estimated_total_cents adds people, storage and optional emails. The same start date and uncharged first month apply. platform_storage_get shows usage and limits (owners, admins and HR). The certified invoice (fatura) has a second line "Armazenamento adicional — N × 0,1 GB".
- Optional emails (reminders and checklist task digests, approval requests, notices of documents people add): 10 per active person per month are included, pooled across the company; above that €1 per 1,000 (€0.10 per block of 100, rounded up), excluding VAT, billed with the people at month end, but only from email.billing_from (the 1st at least 30 days after Bizisy emailed the owners and admins this price; null: not announced yet, nothing is billed); email.billed says whether this month is charged (estimated_total_cents includes it only then); a daily digest counts as one email; never more than the company's monthly limit allows; the same start date and uncharged first month apply. platform_billing_get email shows this month's sent, allowance, blocks and estimate; estimated_total_cents includes it. Owners and admins turn each type's email off or set a monthly limit with platform_notifications_settings_update; the notices stay in the app either way. Sign-in, invite, security, billing and closure emails are never counted. The fatura has a line "Emails de notificação adicionais — N × 100".
- VAT: portuguese_vat (Portugal, or an EU company without a valid VAT number) adds 23 %; reverse_charge (EU company whose VAT number the EU VIES service accepts) and export (outside the EU) add none. details.vat_verification says what VIES answered (invalid: Portuguese VAT applies; unverified_network: VIES was unreachable, unverified_error: VIES refused the check; both keep the format check and VIES is asked again; null on a dry run, where VIES is never asked).
- first_charge_on answers "when am I first charged?" while nothing has been charged yet: the end of the first paid month (e.g. charging starts in November → December is the first paid month → first charge on 1 January). null once charging has begun.
- next_charge_on is the next monthly charge (or invoice); cancel_at means the subscription was canceled and ends then (everything keeps working until that date).
Changing billing details#
- Read them with platform_billing_get (details; when empty, defaults suggests a legal name, country and tax id from the company's first legal entity (source legal_entity) or the company name (source organization), and the caller's email). Confirm suggestions with the user; never invent an address.
- Collect legal_name, vat_number (in Portugal a valid NIF is required: a company or a sole trader, never 999999990), billing email and address { line1, line2?, city, postal_code, country as a 2-letter code }.
- Call platform_billing_update_details with dry_run=true, show the result (including how VAT will apply), wait for a yes, then call it again without dry_run. Send the whole set every time.
Invoices#
platform_billing_invoices_list lists each monthly invoice with its payment status and the certified invoice (fatura) number; the fatura is issued when the invoice is, paid or not, and its receipt when it is paid. A fatura in status pending is still being issued; failed means it is delayed and Bizisy issues it by hand; tell the user it follows. €0 invoices (the uncharged first month) are not listed. Status test means test mode: no certified invoice is issued. Receipts from Stripe are at receipt_url. Billing emails go to the organization's owners and admins; the billing email in the details is printed on invoices.
skill://platform/first-session#
My Workplace (/mcp/me) · read it before your first conversation with this person (they greet you, ask what you can do, or have just connected you): how to welcome them and what to offer.
Read the skill
First session in Bizisy (My workspace)#
Use this when the person has just connected you, greets you, or asks what you can do with Bizisy. You act as them, with their own details and the company directory; you never see other people's private details.
Steps#
- Call platform_whoami. Greet them by first name in one short sentence.
- Say in one or two lines what you can do: answer questions about their own job and contract, their manager and team, look people up in the directory, and update their own contact details after showing a preview.
- Call org_me_get to see what is there (if it says the login is not linked to a person, explain that an owner or admin links it in Bizisy and stop there).
- Offer three concrete things, as a short numbered list, and ask which one they want:
- "When does my contract or probation end?" (from their job, if Bizisy has it).
- "Who is my manager, and who is on my team?" (org_me_team).
- "Add a phone number or an emergency contact" when theirs is missing (preview first).
- When they pick one, do it, previewing every change first.
How to behave#
- The person is in charge. You do the busywork; they decide. Never present yourself as replacing HR or running the company on your own.
- Every change: call the tool with dry_run=true first, show the preview in plain words (what will be created or changed, for whom), and apply it only after the person says yes. Bizisy keeps the preview in Activity too.
- If Bizisy says a change needs approval, say so plainly: it waits for the approver; do not try to get around it.
- After each change, share the view_url so they can check it in Bizisy. Every change and every preview you make is recorded in Activity under your app's name (reads are not).
- Never guess data: read before you write. Treat permission errors as final.
skill://org/setup-company#
HR Assistant (/mcp/manage) · read it before setting up a new company or filling it in bulk: legal entity, locations, teams and people, from a description, a pasted list or a CSV.
Read the skill
Set up a company in Bizisy#
Use this when the user wants to set up their company, or add many locations, teams or people at once, from a conversation, a pasted list or a spreadsheet.
Ground rules#
- Read before you write. Never invent people, emails, dates or managers. If something is missing, ask.
- Every change goes through a dry run first: call the tool with dry_run=true, explain the result in plain language (what will be created or updated, and every warning), wait for an explicit yes, then repeat the exact same call without dry_run.
- Every result has links into Bizisy: view_url for changes, previews and failures, and links to the records touched. After each call, show the user the most relevant one (view_url after a change or a dry run) so they can check it in Bizisy.
- Make changes one at a time: wait for each call to finish before starting the next, and never send writes in parallel. A conflict "The organization is busy right now" means another change collided with yours; retry the same call.
- A forbidden error is final. Tell the user which role they would need (setup needs an owner, admin or HR role) and stop. Do not look for a workaround.
- Dates are YYYY-MM-DD. "Today" is the company's local date, set by its first location.
- You never receive other people's private fields (personal email or phone, address, birthday, emergency contacts) over this connection, and you should not ask the user to paste them.
Procedure#
- Orient. Call platform_whoami, then org_setup_status.
- org_setup_apply and org_people_import_csv need the company to be initialised first. If entity, location or the company root is missing, or a tool tells you to run org_setup_init, call org_setup_init (dry_run=true first, then for real). It creates whatever is missing of the legal entity, a "Head office" location, the company root unit and the user's own person record (title Founder unless owner_title is given). Only owners and admins can link their own login; for anyone else the tool says so in its warnings, and an owner or admin then links it with platform_members_link_person (the warning names the membership_id and person_id). It is safe to call again.
- The "Head office" location and the default legal entity (named after the company) are placeholders. If the user gives the real office or legal details, rename and update them with org_locations_update and org_entities_update instead of adding a second location or entity. Add more only for genuinely additional offices or entities.
- Read what already exists: org_entities_list, org_locations_list, org_units_list and org_people_list with status "all".
- Collect what is missing from the user. For each person the minimum is given name, family name, work email and job title. Also useful: team, the manager's work email, location, start date (default today) and employment type (full_time, part_time, contractor or intern). Ask for the whole list in one message rather than person by person.
- Build one org_setup_apply payload (at most 250 people per call; for more, split them into batches and apply them one after another):
- locations: list of { name, country (2-letter code such as PT), city?, timezone? }
- units: list of { name, kind: division, department or team, parent?: name of the parent unit }. Leave parent out to place a new unit directly under the company.
- people: list of { given_name, family_name, work_email, title, unit?, manager_email?, location?, start_date?, employment_type? } Matching works by name for locations and units (case-insensitive) and by work email for people: existing records are updated, missing ones are created. Parents and managers may be defined anywhere in the same payload. A person's work email is never changed by this tool.
- Call org_setup_apply with dry_run=true. Summarise created and updated counts per type and list every warning.
- On validation_failed, details holds one entry per problem with a path such as people[3].manager_email and a message. Nothing was written. Fix those entries with the user and dry-run again.
- When the user approves, call org_setup_apply again with the same payload and without dry_run. Report the counts.
- If the user has a spreadsheet, ask them to paste it as CSV text and call org_people_import_csv with dry_run=true. You cannot read attached files yourself.
- Columns (any case): given_name, family_name, work_email, title, team, manager_email, location, start_date, employment_type, contract_type, contract_end_date, probation_end_date, weekly_hours, notice_period_days, legal_entity (legal name of an existing entity), and custom fields by their key (org_fields_list). Empty cells leave values unchanged, except an empty manager_email for someone new or moving to another team: their team lead becomes the manager (team_lead_managers says how many); write none in manager_email for no manager. Comma or semicolon separators both work.
- Payroll columns (tax_id, social_security_number, iban) and custom fields with private visibility are refused over this connection: if the file has them, remove those columns and tell the user to import that file in Bizisy (People, Import CSV) instead. Pay is never imported: the user records it on each person's Pay tab. At most 250 people per import: split bigger files into batches of at most 250 people and import them one after another.
- New team names become teams under the company. Locations must already exist (add them first with org_setup_apply).
- If row_errors is not empty, nothing was applied: show each row number and message (row 1 is the header, row 0 means the whole file), get fixes and retry.
- Next steps: offer to invite people. First list who would be invited (name and work email) and wait for the user's yes; then call org_invites_create, one call per person with the person_id from org_people_list. Bizisy emails each invite link to the person's work email; the result's email.status says whether it was sent (tell the user email.message). The link is a sign-in credential and is never returned to you (url is null): when email.status is failed or skipped, tell the user to invite that person again from their profile in Bizisy, where they can copy the link. Finish with org_setup_status and offer org_chart_get to show the result.
- Language: Bizisy speaks English, Portuguese (pt-PT), Spanish, German, French and Italian. If the company works in one of them, an owner or admin can make it the default with platform_language_set_company (dry_run first): everyone who has not picked their own language sees it, and invite and reminder emails use it. People choose their own in My profile (platform_language_set_mine).
Pitfalls#
- Unit names are unique, and the company's own name cannot be reused for a team.
- People with a team and no manager_email get that team's lead as manager (once the team has a lead); give manager_email to choose someone else, or manager_email null (CSV: none) for no manager.
- A manager must be employed (or hired with a start on or before the person's start) on the person's start date, and reporting cycles are rejected.
- org_setup_apply changes the job of an existing person from today. It does not change the start date of someone already employed; it warns instead. Use org_people_correct_job for that.
- People who have left are not changed by org_setup_apply; it warns. Use org_people_rehire if they are coming back.
- Roles of people who already signed in are changed with platform_members_set_role, which only owners and admins can use.
skill://org/manage-people#
HR Assistant (/mcp/manage) · read it before hiring, changing jobs, terminating, rehiring, correcting job history, erasing leavers, inviting people to sign in, planning open positions (headcount), or following change requests that need approval.
Read the skill
Manage people#
Use this for day-to-day HR changes: new hires, promotions and transfers, manager or title changes, people leaving or coming back, fixing wrong history, and giving people access.
Ground rules#
- Find the person first with org_people_list (use q with a name, email or title; status "all" includes leavers). If more than one matches, ask which one. Then read them with org_people_get. Never guess ids.
- Every change: call with dry_run=true, explain who changes, what changes and from which date, wait for an explicit yes, then repeat the call without dry_run.
- Every result has links into Bizisy: view_url for changes, previews and failures, and links to the records touched. After each call, show the user the most relevant one (view_url after a change or a dry run) so they can check it in Bizisy.
- Dates are YYYY-MM-DD in the company time zone. Changes can be future-dated and take effect on their own on that date; org_people_get with as_of shows a future state.
- Over this connection other people's private fields (personal contact, address, birthday, emergency contacts) are never returned to you, even for HR. Their fields come back null. Do not ask the user to paste them unless the task needs them.
- Make changes one at a time: wait for each call to finish before starting the next, and never send writes in parallel. A conflict "The organization is busy right now" means another change collided with yours; retry the same call.
- A forbidden error is final: explain which role is needed and stop. Do not try another tool to get around it.
Which tool to use#
- Someone new: org_people_hire with given_name, family_name, work_email, title and start_date (a future date makes them pre_hire). Optional: unit_id, manager_id, location_id, legal_entity_id, employment_type, fte. Look ids up with org_units_list, org_locations_list, org_entities_list and org_people_list. For many people at once use the setup-company skill instead.
- Promotion, transfer, new manager, new title or FTE change: org_people_change_job with effective_date and reason (promotion, transfer or change). Send only the fields that change. A scheduled termination is kept. Rows already scheduled after that date keep their own values, so check the history first.
- A job row is simply wrong (typo, wrong start date): org_people_correct_job with the job id from the history returned by org_people_get. It is not for real changes. It can also adjust a termination that already has an end date: a later valid_to postpones it, an earlier one moves it earlier within that row, and valid_to null cancels it. It can never close an open-ended row: use org_people_terminate for that.
- Names, work email, phones and other profile data: org_people_update_profile with only the fields that change. Only owners and admins can change the work email of an owner's or admin's login.
- Custom fields of type file (org_fields_list: type file) hold one file each. Upload with documents_field_file_start (person_id, field_key, the file's name, size, content_type, sha256), PUT the bytes to the signed URL, then documents_field_file_finish; it replaces the file the field had. Remove it with org_people_update_profile custom: {
: null }. A value can never be typed in. The file follows the field's tier, and you never get the contents or name of someone else's file over this connection: send the user to Bizisy to open it. CSV imports ignore file columns. - Someone leaves: org_people_terminate with last_day (their last working day, inclusive) and an optional reason. Read the warnings, because direct reports are not reassigned automatically. Offer to move each report with org_people_change_job. Their login keeps working until an admin disables it with platform_members_disable.
- Someone comes back: org_people_rehire with start_date and title.
- Erase a leaver (irreversible anonymisation): org_people_erase, only after every job has ended, and only for owners and admins. It anonymises the person, revokes open invites and disables their login. You cannot erase yourself. Terminate first if they are still employed or scheduled. Confirm explicitly with the user before the real call.
- Sign-in access: org_invites_create needs the person_id from org_people_list (or org_people_get). Before inviting, tell the user who will be invited and wait for their yes. Bizisy emails the link to the person's work email. Read email.status in the result and tell the user email.message: sent means the person has it in their inbox; failed or skipped means nothing reached them, so tell the user to invite them again from the person's profile in Bizisy, where they can copy the link. The link is a sign-in credential and is never returned to API keys or AI apps (url is null). It expires after 14 days, and inviting again revokes the earlier link.
- Roles: member (default), viewer, hr, or admin. HR can invite people as member or viewer only (not hr or admin), and cannot invite someone tied to an owner's or admin's login. Only owners and admins can.
- org_invites_list shows open links (without the link itself); org_invites_revoke cancels one.
- A login that is not linked to its person (their own profile says not linked, or org_setup_init warned): platform_members_link_person with membership_id from platform_members_list and person_id from org_people_list. Owners and admins only.
- Contract terms (contract_type: permanent, fixed_term, temporary, internship or freelance; contract_end_date for fixed_term, temporary or internship; probation_end_date; weekly_hours; notice_period_days) live on the job row: pass them to org_people_hire, or record a change with org_people_change_job (null clears one). Managers and HR see them; colleagues do not.
- Payroll identifiers (tax_id, social_security_number, iban) are private profile fields that can only be changed by signing in to Bizisy, never over this connection: if the user wants one changed, tell them where (People, the person, Edit profile). Every change is emailed to the person and to every owner, admin and HR member.
- Custom fields: org_fields_list shows the organization's own fields (key, type, options, tier). Set values with org_people_update_profile or org_people_hire as custom with the field key, for example custom set to t_shirt_size M; null clears a value. Adding or changing a field definition (org_fields_create, org_fields_update) changes the form for everyone, so confirm the label, type and tier with the user first. Never create fields for health, religion, union membership or other special-category data. Making a field visible to more people while people already have values is refused over this connection: the user confirms that in Bizisy.
- Pay: org_pay_list shows your own pay history and current row. Recording or removing pay (org_pay_add, org_pay_remove) is done only by signing in to Bizisy, never over this connection, and nobody can change their own pay. Over this connection pay is never returned for other people, even for HR: if the user needs it or wants to change it, send them to the person's Pay tab in Bizisy.
- Who is in a team, at a location or reports to someone: org_people_list with unit_id (add include_subunits true for the whole branch), location_id or manager_id (direct reports). Filters combine. Prefer these to reading people one by one. Filtering by legal entity or by who joined or left in a period reveals job details, so it only works for HR signed in to Bizisy (the People list and Reports there), never over this connection.
- The structure: org_chart_get (by manager or by unit, as_of for another date) gives each person's team, location, status, start date, report counts and whether they lead a team; include_upcoming true adds people starting within upcoming_days (default 30). Leaving dates, contract ends and next_change (the next scheduled job change, such as a promotion: {on, reason, title}) appear only for people whose job details the user may see (themselves, their reports, or everyone for HR), as in org_people_get. is_unit_head is who leads a team today (its team lead).
- Team leads: org_units_set_head with unit_id and person_id (null removes the team lead), dry_run=true first, then confirm. Say "team lead" to the user (the API calls it head). What it means, so explain it when choosing one: people who join the team later get the team lead as manager unless a manager is given, and when a change needs the manager's approval and the person has no manager, the team lead decides. Setting a lead changes no one's manager today. Suggest people already in that team first (org_people_list with unit_id and include_subunits true); the lead must work here today or be starting. Tell the user who stops being lead (previous_head) and which other teams the person already leads (also_heads). It needs no approval. If the user also wants the person moved into the team, that is a separate job change: org_people_change_job with unit_id and an explicit manager_id (usually the parent team's lead, or their current manager; without manager_id the team's current lead would become their manager), and it may need approval. Never move someone without being asked: by default a lead keeps their own team.
- Default manager: hiring (org_people_hire), rehiring, or moving someone into another team (org_people_change_job with unit_id) without manager_id makes that team's lead the manager (the parent team's lead when the person is that lead; nothing when the team has no lead); manager_default in the result says so: tell the user ("Rita Alves, team lead of Engineering, will be their manager"). Ask the user who the manager should be when it matters, and send manager_id, or null for none. CSV imports and org_setup_apply do the same for an empty manager (team_lead_managers counts them).
- To hand over the chart as a list or spreadsheet: org_chart_export (format "csv" for a CSV file, "json" for rows; root_person_id for one person's branch, unit_id for a team and its sub-teams). It has name, title, team, manager, location, status, start date, level and report counts, never job details. Pictures and PDFs of the chart are made in the app: Org chart → Export.
- "What needs my attention?", "who starts or leaves soon?", "what's coming up?": org_home_summary. It lists first days to prepare (not invited yet), probation and contract ends, people leaving (and how many reports still need a new manager), people never invited, teams without a team lead, and the next 60 days of dated events, with person ids for follow-up calls. Items disappear once the data changes; there is nothing to mark done.
- Profile photos: org_people_photo_upload with person_id and image_base64 (the image file as base64: JPEG, PNG or WebP, at most 2 MB; Bizisy crops it to a square and drops its metadata). Only upload a photo the user gave you for that person and confirms is theirs to share, since everyone in the organization sees it. org_people_photo_remove deletes it. photo_url in people results is the photo's path on the company address. The company logo (owners and admins): platform_appearance_logo_upload and platform_appearance_logo_remove; it shows on the sign-in page too.
- What is coming up (probations ending, fixed-term contracts ending, people starting, work anniversaries): org_reminders_upcoming with days (default 30, at most 90). It lists only the reminders that are on, with the day each email goes out.
- Reminder emails: Bizisy emails these to the HR group (owners, admins and HR) and to each person's manager once a day. org_reminders_get shows the settings; org_reminders_update changes them (per reminder: enabled, lead_days, on_first_day for starters, notify_hr, notify_manager, and notify_person for anniversaries). Defaults: probation 14 days before, contracts 30 days before, starters 7 days before plus the first day, anniversaries off. Dry-run first and confirm with the user, since it changes who gets emails. Probation and contract reminders need the dates on the job (probation_end_date, contract_end_date).
- Notifications: a notification of kind unavailable could not be checked just now; it is kept, so try again later. Every reminder, checklist task email, approval request and "a person added a document" notice also lands in each recipient's Bizisy notifications (platform_notifications_list for the caller's own; mark them read with platform_notifications_mark_read or _mark_all_read). Owners and admins choose which of these are also emailed with platform_notifications_settings_get / _update (email per type: reminders, approval_request, document_uploaded; extra_limit: a monthly cap on extra emails, null for none). 10 optional emails per active person per month are included; above that €1 per 1,000 (€0.10 per 100), excluding VAT, once paid billing runs. Dry-run first and confirm: turning an email off means people only see it in the app.
- Approvals: the company may require approval before job changes, terminations or pay changes take effect (org_approvals_settings_get shows who approves each: off, hr, manager, or manager_then_hr; in manager modes, a person with no manager has the team lead of their team, or of a team above, decide instead, and HR when there is none who can — the result's approval.team_lead names the team). Then org_people_change_job, org_people_terminate and org_pay_add do not change anything yet: the result's approval says the request is pending and who approves it (approval null means the change applied; status approved with automatic true means the proposer is the only person who can approve as HR, so it applied at once). The same goes for org_people_correct_job on the current or a scheduled job (or a last day moved or cancelled), org_people_rehire and org_pay_remove of the pay in force or a scheduled one; corrections of jobs that ended before today apply at once. While approval is on for job changes, org_setup_apply and org_people_import_csv can add new people but are refused if they would change an existing person's job: propose those one by one. Tell the user plainly: "Sent for approval to Bea Silva; it takes effect from 1 November once approved." Nobody can propose a change about themselves while approval is on, and a request you proposed (through this connection or in Bizisy) is always approved by someone else. A person can have one open job request and one open pay request at a time; a conflict naming an open request means decide or withdraw it first. org_approvals_list (status open, closed or all; person_id; waiting_for_me) and org_approvals_get show requests, their steps and comments. Approving and rejecting (org_approvals_approve, org_approvals_reject) is refused over this connection: a person must decide in Bizisy (Approvals), so send the user there. You may withdraw a request with org_approvals_cancel (one you proposed, or any as owner, admin or HR) after the user confirms. A correction must not change the last day and job fields together while approval is on: send them separately. A rehire that would cancel a scheduled termination is refused while terminations need approval: correct the last day instead. Nobody can change their own job while it needs approval or while a request about them waits. Changing who approves (org_approvals_settings_update) is also only in Bizisy.
- Numbers about the workforce (headcount, joiners, leavers, turnover per month, breakdown by team, location, entity, employment or contract type): org_reports_headcount with from_month and to_month as YYYY-MM. Its planned field is the headcount plan: people employed today plus open positions (drafts and on-hold ones are not counted), and each breakdown row has open, the open positions in that group.
Open positions (headcount planning)#
- A position is a role the company plans to fill: title, team, location, legal entity, who it reports to (a person, or another position for a team that does not exist yet), contract type, weekly hours, target start date, status (draft, open, on_hold, filled, cancelled), notes, and reason: new or replacement (optionally naming the leaver with replaces_person_id).
- See the plan with org_positions_list (default: draft, open and on hold; status all includes filled and cancelled) and one with org_positions_get. Owners, admins and HR see every position; a manager sees only the open and on-hold ones in their own line; others see none.
- Create one with org_positions_create (dry_run=true first, then confirm). Look ids up with org_units_list, org_locations_list, org_entities_list and org_people_list. Put no personal data in notes.
- Change one, or move it between statuses, with org_positions_update: draft to open, on hold or cancelled; open and on hold back and forth; cancelled to draft or open. Positions are never deleted: cancel the ones no longer needed (the roles under a cancelled one move up to whoever it reported to). Filled and cancelled positions come a page at a time: org_positions_list with status closed (or filled, cancelled, all) and after = the last id you got.
- A hire that fell through (terminated on or before their start date, or erased): can_reopen is true on the filled position; reopen it with org_positions_reopen (dry_run=true first) and the roles that had moved under that person come back under it.
- Someone leaving with open roles under them: org_home_summary lists move_roles; move each role with org_positions_update (reports_to_person_id) before the last day. People hired into a role that reported to another open role start without a manager: no_manager lists them; set one with org_people_change_job.
- The budget (pay_range) is pay data: over this connection it is never returned (pay_range_hidden is true) and setting it is refused. If the user wants to set or change it, send them to Positions in Bizisy.
- To fill a position, hire the person with org_people_hire and position_id (only open or on-hold positions). Copy the title, team, manager, location, legal entity, contract type and weekly hours from the position unless the user says otherwise. The position becomes filled and positions that reported to it then report to the new person. Moving someone already employed into a position is not a fill: cancel the position and use org_people_change_job.
- org_chart_get with include_positions true shows the open roles in the chart; org_home_summary counts open, on-hold and draft positions and those past their target start.
- A list of people as a spreadsheet: org_people_export_csv returns the CSV text and a filename (pay is never included; private fields only from the app). To answer a person's request for their own data, they can use Download my data in their profile; HR can download a person's full data from their page in Bizisy (org_people_export_data works over this connection only for yourself).
- Who changed what about someone (profile, job, termination, pay, invites, login link): platform_activity_list with subject_id set to their person id; each entry has a summary, who did it and when. Owners, admins and HR see every change; others only their own. Entries never name the person, so erased people stay anonymous.
- Roles of people who already signed in: platform_members_list, then platform_members_set_role. This is for owners and admins only, and only owners can grant or remove the owner role. HR cannot make anyone an admin.
- Closing the company, or downloading all of its data at once: never over this connection. platform_org_status tells whether the account is active or closing (and when its data will be deleted). If the user wants to close it or get everything, send them to Manage → Settings → Close account (owners; it explains what is deleted and kept, offers the full download first and asks for a fresh sign-in) or Settings → Data & privacy → Download all company data (owners and admins). Closing signs everyone out, ends this connection (its API key or its sign-in) and deletes all data 14 days later unless an owner reopens it from the emailed link.
- AI apps connected by signing in: platform_connections_list lists your own (owners and admins: everyone=true for the whole company, with who connected each); platform_connections_revoke disconnects one at once. Confirm with the user first, and say so when the one they name is this very connection: this conversation then loses access. To connect another app, send the user to Settings → Connected apps; apps cannot connect apps.
Checklists (onboarding, offboarding and custom)#
- Hiring (org_people_hire, org_people_rehire) starts the onboarding checklists that start by themselves and match the person; terminating (org_people_terminate) starts offboarding. Nothing starts for a start date or last day more than 30 days ago, nor for bulk imports. A corrected start date or last day moves the open tasks with it.
- Templates: org_checklists_templates_list shows them (the two starter templates are listed with saved false until the company changes anything). Create one with org_checklists_templates_create, change one with org_checklists_templates_update (tasks replaces the whole list: send every task to keep, with its id), archive or restore with org_checklists_templates_archive. Each task has a title, an optional description and an https link_url, an assignee (hr, manager, person, or member with a person_id) and offset_days relative to the start date (onboarding), the last day (offboarding) or the chosen date (custom); negative means before. conditions limit a template to unit_ids (with their subunits), location_ids and legal_entity_ids. Confirm templates with the user before saving: they change what happens on every future hire.
- Start one by hand: org_checklists_runs_start with person_id and template_id (anchor_date to use another date). Cancel with org_checklists_runs_cancel.
- Offboarding is discreet: until HR shares it (org_checklists_runs_share), the person leaving and colleagues given a task see each task only from its visible_from date (7 days before it is due by default, visible_days on the template task). Never tell a colleague about someone's departure before HR has. Checklists started by hand keep their date; automatic ones follow corrections to the start date or last day.
- What is open: org_checklists_runs_list with person_id for one person (progress and every task), or org_checklists_tasks_list with scope mine, team or all and due_by (for example today, for everything due or overdue).
- Work on tasks: org_checklists_tasks_set_status (done, open, or skipped with a reason), org_checklists_tasks_reassign, org_checklists_tasks_comment. Dry-run first and confirm. Never put health or other sensitive details in comments or skip reasons.
- Task emails: org_checklists_settings_get and org_checklists_settings_update (email_tasks) turn the daily task emails on or off; they go with the reminder emails.
Errors and what to do#
- conflict "already starts on": a row begins that day; use org_people_correct_job on it.
- conflict "not employed on": the date is before their start or after their last day.
- conflict "reporting cycle": the proposed manager reports (directly or indirectly) to this person. Change that relationship first.
- conflict about a manager not employed on that date: pick someone who is.
- conflict on a work email: someone already uses it; find and update that person instead.
- conflict "open-ended": the row has no end date; use org_people_terminate.
- conflict "already has a login" (invite): they can already sign in; nothing to send. Change their role with platform_members_set_role if needed.
- conflict "has left the company" (invite): rehire them first with org_people_rehire, then invite.
- conflict about an existing membership's role (invite): call org_invites_create again without role to keep their current role, or change the role with platform_members_set_role (owners and admins only).
- validation_failed: details lists each bad field; fix them and dry-run again.
- conflict "already has a … waiting for approval": details.approval_id is the open request; show it with org_approvals_get.
- conflict "This change can no longer be applied" (seen by approvers in Bizisy) or a request outdated or expired: propose the change again.
skill://org/my-profile#
My Workplace (/mcp/me) · read it before reading or updating your own profile, or looking up your team and colleagues.
Read the skill
My profile and my team#
Use this when the user asks about themselves ("update my phone", "who is my manager", "add an emergency contact") or wants to find a colleague.
Ground rules#
- You act as the signed-in person, on their own data. Job title, team, manager, given and family names and work email are managed by HR: if the user wants those changed, say so and suggest asking HR. You cannot change them.
- Start with platform_whoami if you need to know who is signed in, then read with org_me_get. For any change, call org_me_update with dry_run=true, show only the fields that will change (before and after), wait for a yes, then repeat without dry_run.
- Every result has links into Bizisy: view_url for changes, previews and failures, and links to the records touched. After each call, show the user the most relevant one (view_url after a change or a dry run) so they can check it in Bizisy.
- Personal email and phone, address, birthday and emergency contacts are private. Repeat them only to the person themself, and only when relevant.
- About colleagues you only get public information. Never try to work out anyone's private details.
- A forbidden error is final: explain it and stop.
- Your own pay history is in org_pay_list with your own person id (from org_me_get). Never ask about or try to read anyone else's pay.
- To give the user a copy of everything Bizisy holds about them, call org_me_export_data; it returns the data and a filename. Offer to summarise it rather than pasting all of it.
Update my details#
- org_me_get.
- Build the smallest org_me_update payload, with only the fields that change. null clears a field. Only these fields can be edited: preferred_name, pronouns, work_phone, personal_email, personal_phone, address, birthday, emergency_contacts. Payroll details (tax_id, social_security_number, iban) can only be changed by the person signed in to Bizisy (My profile, Edit my details), never over this connection. Anything else, including custom fields and contract terms, is managed by HR, except custom fields of type file that your company lets people fill in (org_fields_list: type file, file.self_upload true): upload yours with documents_me_field_file_start, PUT the bytes, then documents_me_field_file_finish (it replaces the old file and counts toward your monthly own-file limit), or remove it with documents_me_field_file_remove after the user confirms.
- address needs line1, city and country (2-letter code); line2 and postal_code are optional.
- emergency_contacts replaces the whole list. Keep existing contacts the user did not mention removing; at most 5, each with name, relationship and phone.
- birthday is YYYY-MM-DD.
- Call it with dry_run=true, show the result, and commit after the user agrees.
- Confirm in one sentence what changed.
My photo#
- org_me_photo_upload sets your profile photo from image_base64 (the image file as base64: JPEG, PNG or WebP, at most 2 MB). Bizisy crops it to a square and removes its metadata; everyone in your organization can see it. Dry-run it first (dry_run=true checks the image without saving), then upload after the user agrees. org_me_photo_remove deletes it. Usually it is easier for the user to do it in Bizisy (My profile, Add a photo), where they can frame it.
My language#
- platform_language_set_mine sets the language Bizisy uses for you (the web app and your emails): en, pt-PT, es-ES, de-DE, fr-FR or it-IT; null follows the company default. platform_whoami shows your choice (user.language) and the company default (org.language). Dry-run first, then apply after the user agrees. Keep talking to the user in their own language whatever Bizisy uses.
My team and colleagues#
- org_me_team gives the manager, peers (same manager) and direct reports as of today.
- To find someone, call org_people_list with q (name, email or title), then org_people_get for details.
- org_chart_get shows the structure, by "manager" (default) or by "unit". Each person has their team, location, start date, and how many people report to them directly and in total; include_upcoming true also shows people starting in the next 30 days (upcoming_days changes that, up to 365). For you and your reports it also gives leaving_on, contract_end and next_change (the next scheduled job change, such as a promotion). To list someone's direct reports or a team's members, org_people_list with manager_id or unit_id is simpler.
- To hand over the chart as a list or spreadsheet: org_chart_export (format "csv" for a CSV file, "json" for rows; root_person_id for one person's branch, unit_id for a team and its sub-teams). It has name, title, team, manager, location, status, start date, level and report counts, never job details. Pictures and PDFs of the chart are made in the app: Org chart → Export.
- If you manage people, org_positions_list shows the open and on-hold positions HR is planning in your line (roles still to be filled), and org_chart_get with include_positions true places them on the chart. Only HR creates or changes positions.
Approvals (managers)#
- If the company asks managers to approve changes for their reports, org_approvals_list (waiting_for_me true) shows what waits for the user and org_approvals_get shows one request. Approving and rejecting happen only in Bizisy (Approvals in their workspace): send the user there; never try to approve over this connection.
My tasks#
- org_checklists_tasks_list (scope mine, the default) lists the checklist tasks assigned to you, soonest due first, including tasks about yourself on your onboarding (for example completing your profile). Managers can use scope team for the checklists of the people who report to them; org_checklists_runs_list with person_id shows one person's checklist with its progress.
- Tick a task with org_checklists_tasks_set_status (status done; open unticks it) and add a note with org_checklists_tasks_comment. Call with dry_run=true first and confirm with the user. Skipping a task or giving it to someone else is for HR and managers.
- Each task can carry a link (link_url) from HR, for example to the handbook: share it with the user as it is.
My notifications#
- platform_notifications_list shows the user's own notifications, newest first: reminders (their work anniversary; for managers, their reports' probation, contract end and start dates), checklist tasks due, and changes waiting for their approval. Each has an href to open it in Bizisy. limit 0 returns only the unread count; unread_only filters.
- Mark them read with platform_notifications_mark_read (ids) or platform_notifications_mark_all_read when the user says so. Their company decides which notices are also emailed; the notifications are there either way.
Connected apps#
- platform_connections_list lists the AI apps you connected by signing in; platform_connections_revoke disconnects one at once (confirm with the user first; disconnecting this very connection ends this conversation's access). New apps are connected from Connect AI in Bizisy, never over this connection.
When something fails#
- not_found "not linked to a person record": this login has no person yet; ask HR to send an invite or link the login.
- validation_failed: details names the bad fields; fix them and dry-run again.
- forbidden: explain and stop.
skill://documents/manage-documents#
HR Assistant (/mcp/manage) · read it before adding, finding, sharing or deleting company and people's documents (contracts, certificates, ID copies, policies, the handbook).
Read the skill
Documents#
Person documents (contract, addendum, certificate, ID copy…) belong to one person; company documents (handbook, policies…) belong to the company. Each has a category and a visibility chosen when it is added.
Ground rules#
- Person documents are private and can hold sensitive data (ID copies, medical certificates). Through this connection you see other people's documents as metadata only (title, category, date, size; access = "metadata"): you can list them and add new ones, but never read or download their contents. Send the user to Bizisy (the person's Documents tab) to open one. Never guess what a document says.
- Company documents shared with everyone can be downloaded here.
- For any change call the tool with dry_run=true first, show what will happen, and only then call it again.
- Every result carries links into Bizisy; show the most relevant one after a change.
Visibility#
- Person documents: hr (owners, admins and HR only), hr_person (default: also the person, in Me → My documents), hr_person_manager (also their managers).
- Company documents: everyone (default), managers (people with reports, and HR), hr.
- A document the person added themself ("From me", uploaded_by = self) stays hr_person.
Find documents#
documents_list with person_id (one person; find the id with org_people_list), scope company, category, or q (words in the title). sort=largest shows what takes the most space.
Add a document (two calls and one upload)#
- documents_upload_start with subject ({kind: "person", person_id} or {kind: "company"}), category (see categories in documents_list), optional title, visibility, expires_on (YYYY-MM-DD) and notes, and the file's name, size, content_type and sha256 (lowercase hex). Dry-run it first.
- Upload the bytes within 15 minutes: PUT the file to upload.url with exactly upload.headers (they fix the size: any other size is refused). You usually need the user's computer or a script for this step; if you cannot upload files, tell the user to add it in Bizisy (drag and drop on the person's Documents tab).
- documents_upload_finish with the document id. A file whose bytes don't match is refused and deleted: start again. Accepted: PDF, PNG, JPEG, WebP, HEIC, DOCX, XLSX, ODT, ODS, TXT, CSV. Refused: macros, archives, executables, SVG.
Change or delete#
documents_update changes title, category, visibility, expires_on or notes; documents_delete deletes it for good.
Storage and limits#
The largest file, the company's storage ceiling and how much people may add themselves each month are in Settings → Storage (platform_storage_get; owners and admins change them with platform_storage_set_limits). The first 500 MB are included; above that storage costs €1 per GB per month (€0.10 per 0.1 GB, excluding VAT), on the month's highest size, with the monthly invoice. An upload over a limit is refused with a message naming the limit: pass it on.
Custom file fields#
A document with field set is the file of a custom field (org_fields_list, type file): its visibility and category follow the field, so documents_update refuses them (title, expiry and notes are fine). Deleting it empties the field. Put a file in a field with documents_field_file_start / documents_field_file_finish (see the manage-people guide).
Categories#
documents_categories_get lists them; documents_categories_set replaces the company's own (beside the starter list).
Errors#
- forbidden on a download: the contents are only available in Bizisy; send the user there. Do not retry.
- payload_too_large / conflict (storage full, monthly limit): explain the limit and where it is changed.
skill://documents/my-documents#
My Workplace (/mcp/me) · read it before finding your own documents (contract, certificates) and company documents, or adding a document of your own for HR.
Read the skill
My documents#
Read#
- documents_me_list (scope mine, the default): your documents that HR shared with you, and the ones you added yourself ("From me"). scope company: company documents for you (handbook, policies). Someone who reports to you: person_id, for the documents HR shared with their managers.
- documents_me_download returns a link valid for 5 minutes that downloads the file. Never store or forward the link; ask again when it expires. Downloading a person document is recorded in Activity.
- Documents can hold private data: repeat their details only to the person they are about.
Add one for HR ("From me")#
Only you and your HR team see it, and HR is emailed when it arrives (the email never names the file).
- documents_me_list: self_upload says whether you may add files this month and how much is left.
- documents_me_upload_start with category (default Other), optional title and expires_on, and the file's name, size, content_type and sha256 (lowercase hex). Dry-run it first.
- Upload the bytes within 15 minutes: PUT the file to upload.url with exactly upload.headers. If you cannot upload files, tell the user to add it in Bizisy (Documents → From me).
- documents_me_upload_finish with the document id. Accepted: PDF, PNG, JPEG, WebP, HEIC, DOCX, XLSX, ODT, ODS, TXT, CSV. You cannot change or delete what you added; ask HR. Files in custom fields your company lets you fill in (documents with field set) are uploaded, replaced and removed with documents_me_field_file_start / _finish / _remove; they count toward the same monthly limit.
skill://webhooks/webhooks#
HR Assistant (/mcp/manage) · read it before setting up, testing or troubleshooting webhooks (sending Bizisy events to another system): endpoints, event types, secrets, the delivery log
Read the skill
Webhooks#
Webhooks tell another system (payroll, IT provisioning, Zapier, a data warehouse) when something changes in Bizisy. Only owners and admins can manage them.
Set one up#
Adding an endpoint, changing its URL, adding events, turning it on, rolling its secret and deleting it happen in the Bizisy app only (Manage → Settings → Webhooks), by a signed-in owner or admin; over this connection they are refused. Every owner and admin is emailed when an endpoint is added or sends to a new host.
- Ask which system should receive events and which changes it needs. List the types with webhooks_events_list (person.hired, person.updated, person.job_changed, person.terminated, person.rehired, person.erased, unit., location., legal_entity.*, position.created, position.updated, position.filled, approval.decided, checklist.started, checklist.completed, document.added, document.updated, document.deleted, member.invited, member.joined, member.role_changed) and tell the user what to pick.
- Ask the user to add the endpoint in Settings → Webhooks; the signing secret is shown to them once, there.
- Then you can send a test event (webhooks_endpoints_test) and check webhooks_deliveries_list after about a minute.
What is sent#
A POST with JSON { type, timestamp, data }. data has organization_id, the ids and dates of the change and, for people and structure records and open positions, their public and job details as they are when the attempt is sent (never private or pay data, nor a position's budget or notes). Approval and checklist events carry ids, kinds and dates only; approval.decided is sent once a job change or termination request is approved or rejected, never while it waits. Delivery may repeat (dedupe on webhook-id) and may arrive out of order. Headers follow Standard Webhooks: webhook-id, webhook-timestamp, webhook-signature (v1,<base64 HMAC-SHA256 of "id.timestamp.body">). The receiver must answer 2xx within 10 seconds; redirects are not followed.
Troubleshooting#
- Deliveries are tried 8 times over about a day. error says why: dns, blocked_address (the host resolves to a private address), connection, tls, timeout, redirect, http_status (not 2xx; see response_status).
- After a day of only failures Bizisy turns the endpoint off (disabled_reason failing) and emails owners and admins. Once the receiver is fixed, the user turns it back on in the app; then you can resend what is needed (webhooks_deliveries_resend).
- A leaked secret: turn the endpoint off now (webhooks_endpoints_update enabled false) and ask the user to roll the secret in the app with "Stop the old secret now".
Something missing or wrong on this page? Write to hello@bizisy.com.