MCPInstall

pipefy-portal-setup

Use this skill when the user wants to list, create, or configure Pipefy portals (main hub, pages, page elements, sub-portals, publish/unpublish). Uses Interfaces and internalapi. Not for pipes/cards.

Installs
684
Last 24h
+10
Trending rank
#8625
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/pipefy/ai-toolkit --skill pipefy-portal-setup
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads pipefy-portal-setup automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Portal setup

MCP clients: read references/mcp.md. CLI users: read references/cli.md. Examples below describe shared operation arguments.

Configure an organization's Pipefy portal: bootstrap the main hub, add pages and widgets, wire and publish sub-portals (Interfaces GraphQL + internal_api for sub-portal wiring).

Deep reference: docs/mcp/tools/portal.md. Parity matrix: docs/parity.md. Env vars: docs/config.md.


When to use

  • "Create our company portal", "list portals for org X", "publish a sub-portal".
  • Add or change portal pages, layout, or page elements (forms, link, etc.).
  • Attach, publish, unpublish, or delete sub-portals on the main portal.

Do not use for:

  • Pipes, phases, cards, or automations — see pipefy-pipes-and-cards, pipefy-automations.
  • Raw GraphQL when a portal tool exists — prefer the tools below.
  • Bootstrapping a portal via undocumented createInterface GraphQL — always use create_portal.

Prerequisites

  • Organization id: UUID or numeric org id from the organization lookup or the Pipefy URL (examples below use fictional 123456789 per fixture_ids.py). SDK resolves numeric ids before Interfaces calls. The org you pass to list_portals / create_portal must be the same org your token can write on.
  • Portal writes: token needs create_portal and/or manage_portals on that org. Many service accounts only have pipe/card scope on their default org → PERMISSION_DENIED on portal mutations even when reads succeed elsewhere.
  • One main portal per org — create_portal is idempotent (second call returns the same portal UUID).

Confirm access before writes

Reads on the wrong org can succeed while Interfaces writes fail. Before page/element/sub-portal mutations:

  1. Call list_portals with the intended organization_uuid.
  2. Ensure the token is meant for that org (service account email vs human user on a different org is a common mismatch).
  3. Prefer an org where the account has manage_portals and portal admin in Pipefy (not only canManagePortals on a read query from another org).

If update_portal or delete_portal returns PERMISSION_DENIED but the user insists the org role is correct: Pipefy may require joinAsAdmin on that portal interface for service accounts (Interfaces mutation, not shipped as MCP/CLI). The user must join as portal admin once in the UI (or via GraphQL) per portal UUID before SA writes succeed.


How portals are organized

ConceptWhat to expect
Main portalAt most one per org (subType: portal). Created with create_portal (findOrCreateInterfaceByTemplate).
list_portalsUsually one row — the main portal only (filter portal). Sub-portals do not appear here.
Sub-portalsSeparate entities (create_sub_portal). Listed under get_portal → subPortals[].
UI on the main hubCreating sub-portals does not add tiles to the main page. You must publish (or attach) on a forms element via publish_sub_portal / update_sub_portal_element.
End-user visibilitySub-portals with published: false exist in the API but are invisible to portal visitors until published.
Public main hubMain portal published is always true on get_portal. Public access = update_portal(visibility="public"), not the published flag.

Main portal lifecycle

  • Prefer update_portal on an existing main portal over delete + create_portal on orgs you reuse for testing.
  • delete_portal on the main removes one interface UUID; orphan sub-portals can remain unless deleted first.
  • After deleting the main, create_portal may fail with Menu already created (org menu state persists while mainPortal is null). Recovery: delete orphan sub-portals, use Pipefy admin/support, or bootstrap content on the surviving UUID — do not switch to raw createInterface, which leaves a skeleton main page ("Page", 0 elements) and a broken builder; idempotent create_portal will keep returning that UUID.

Empty main page

If get_portal shows a main page with no elements, call create_portal_page with title only (no elements in the request). The API typically returns a page with ~14 templated widgets (text, forms, links, etc.). Use that page for publish slots and element tests. Do not pass type: subPortal inside create_portal_page — validation fails at create time.


Schema notes

TopicRule
published on listlist_portals does not return published — call get_portal.
Sub-portal in layoutTiles may appear under pages[].elements[] with type: subPortal even when top-level subPortals[] is empty.
Publish wireUse publish_sub_portal / update_sub_portal_element on an existing forms element (updateSubPortalElement on internal_api). create_portal_element with type: subPortal is not a substitute for publish.
Element metadataupdate_portal_element is replace-all — send the full metadata JSON every time.
Element data sourcesEvery update_portal_element passes data_sources or portal_uuid, whatever the element type; omitting both is rejected. data_sources is replace-all: [] unlinks the element from its pipe or table, and is the one-call choice for an element with no bindings (link, text). To keep bindings, omit data_sources and pass portal_uuid (the uuid you passed to get_portal, whose pages[] holds page_id); the element's dataSources and editable flag are sent back.
Metadata keysforms → name (not formId); link → linkName / linkUrl (not url / label).
Layout JSONupdate_portal_page_layout expects an array of row objects. Each row needs a non-empty id, type: "row", and children as non-empty strings. Copy the target pages[].layout from get_portal. metadata.gridMap gives element dimensions, not placement. The API stores any JSON here verbatim, so a wrapper or an incomplete row replaces the grid. The toolkit rejects a non-array and any incomplete row locally, and still accepts [] as an empty page; never bypass it with raw GraphQL.
Page grid vs elementscreate_portal_element leaves the layout grid untouched unless you pass element_id + layout (existing rows plus a row listing the new id); duplicate_portal_element appends layout rows; delete_portal_element leaves layout refs unless you pass layout (existing rows with the element removed); orphan refs can break the portal viewer (HTTP 500).

Tools needed

OperationRead-only
list_portalsYes
get_portalYes
create_portalNo
update_portalNo
delete_portalNo
create_portal_pageNo
update_portal_pageNo
delete_portal_pageNo
sort_portal_pagesNo
update_portal_page_layoutNo
create_portal_elementNo
update_portal_elementNo
delete_portal_elementNo
duplicate_portal_elementNo
create_sub_portalNo
update_sub_portal_elementNo
publish_sub_portalNo
unpublish_sub_portalNo
delete_sub_portal_elementNo
delete_sub_portalNo

Element type values (15): text, table, field, embedLink, embedVideo, embedImage, button, divider, link, forms, pages, subPortal, automationButton, contentBlock, document.


Steps — happy path (main portal + sub-portal publish)

  1. List or bootstrap the main portal

    Operation arguments:

    list_portals(organization_uuid="123456789")
    

    Expect at most one main portal row. If none:

    Operation arguments:

    create_portal(organization_uuid="123456789")
    

    Capture uuid where subType is the main portal.

  2. Inspect structure

    Operation arguments:

    get_portal(portal_uuid="<MAIN_PORTAL_UUID>")
    

    Note pages[], elements[], and forms element ids. If the main page has zero elements, run create_portal_page (title only) on that portal before adding widgets.

  3. Optional — add a forms element (if no templated forms slot exists)

    Operation arguments:

    create_portal_element(page_id="<PAGE_ID>", type="forms", metadata={"name": "Request access", "gridMap": {"height": 66, "columns": 4, "minColumns": 4}})
    

    If create_portal_element returns an opaque or INTERNAL_SERVER_ERROR from Interfaces, duplicate_portal_element from an existing link on the same portal_uuid and page_id instead of retrying create blindly.

  4. Create a sub-portal

    Operation arguments:

    create_sub_portal(main_portal_uuid="<MAIN_PORTAL_UUID>", name="Partner hub")
    

    Capture the sub-portal uuid. get_portal will list it under subPortals[] with published: false — the main hub UI is unchanged until step 5.

  5. Publish on a forms element

    Operation arguments:

    publish_sub_portal(portal_uuid="<MAIN_PORTAL_UUID>", element_id="<FORMS_ELEMENT_ID>", sub_portal_uuid="<SUB_PORTAL_UUID>")
    
  6. Verify publish state

    Operation arguments:

    get_portal(portal_uuid="<MAIN_PORTAL_UUID>")
    

    Success: target subPortals[].published is true. End users can see the sub-portal only after this (and hub visibility rules).

  7. Optional — make the main hub public

    Update <MAIN_PORTAL_UUID> with visibility="public" through update_portal (SDK argument: interface_uuid; MCP argument: portal_uuid).


Steps — pages, layout, and safe edits

Use a disposable page for element/layout experiments on a shared org main portal:

  1. create_portal_page with a unique title (e.g. Agent smoke 2026-06-01).
  2. Run create_portal_element, update_portal_element, duplicate_portal_element, update_portal_page_layout on that page only.
  3. Review and approve deletion of the disposable page, then use delete_portal_page.

duplicate_portal_element: element_id, portal_uuid, and page_id must refer to the same page that already contains the source element (duplicate on the same page, not cross-page).

update_portal_page_layout: read the target pages[].layout from get_portal and preserve its row IDs, child element UUIDs, and unaffected rows. Send the complete array with only the intended order/grouping changes; then re-read and compare. elements[].metadata.gridMap (height, columns, minColumns) describes dimensions, so it cannot reconstruct row order or grouping. Preserve the full metadata when resizing an element. If the layout is unavailable, stop the positional edit instead of guessing. Never wrap the array in { "rows": [ ... ] }.

MCP:

get_portal portal_uuid="<portal_uuid>"
update_portal_page_layout page_id="<page_uuid>" layout=[<complete edited rows from that page>]
get_portal portal_uuid="<portal_uuid>"

CLI:

pipefy portal get <portal_uuid> --json
pipefy portal page layout update --page-id <page_uuid> --layout '[<complete edited rows from that page>]' --json
pipefy portal get <portal_uuid> --json

create_portal_element with placement: read pages[].layout, generate a UUID for element_id, append or insert a row { "id": "<new row uuid>", "type": "row", "children": ["<element_id>"] }, and pass both element_id and the complete layout. Without layout the element is created but stays off the grid. Re-read and compare.

MCP:

create_portal_element page_id="<page_uuid>" type="link" metadata={...} element_id="<element_id>" layout=[<existing rows>, {"id": "<row uuid>", "type": "row", "children": ["<element_id>"]}]

CLI:

pipefy portal element create --page-id <page_uuid> --type link --metadata '{...}' --element-id <element_id> --layout '[<existing rows>, {"id": "<row uuid>", "type": "row", "children": ["<element_id>"]}]' --json

delete_portal_element with pruning: read pages[].layout, remove element_id from every row's children, and pass the complete array as layout. The grid and the element change in one call, so no row is left pointing at a deleted element. A layout that still lists element_id is rejected. Re-read and compare. The MCP and CLI references show the delete call with layout.

sort_portal_pages: pass a non-empty page_ids list with no duplicates. If the response exposes nested success: false, treat the operation as failed.

Link element metadata (create/update, full replace):

{
  "gridMap": { "height": 64, "columns": 4, "minColumns": 4 },
  "linkUrl": "https://example.com",
  "linkName": "Example link"
}

A link has no bindings, so its update also passes data_sources: [] (CLI --data-sources '[]').


Steps — unpublish or remove sub-portal

Unpublish (keeps sub-portal entity; visitors lose access):

Operation arguments:

unpublish_sub_portal(portal_uuid="<MAIN_PORTAL_UUID>", element_id="<FORMS_ELEMENT_ID>")

Detach element wiring with delete_sub_portal_element after reviewing the impact and obtaining approval.

Delete sub-portal interface with delete_sub_portal (irreversible); review and approve before deletion.


Success criteria

  • list_portals returns the org main portal (typically one row); create_portal returns the same UUID on repeat.
  • get_portal shows expected pages / elements after writes.
  • After create_sub_portal, sub-portal exists in API but published: false until publish.
  • After publish: subPortals[].published is true and the main page shows the wired forms slot.
  • After unpublish: published is false without deleting the sub-portal entity (unless you called delete_sub_portal).
  • After layout/element edits on a disposable page, main portal pages used in production still open in the builder (no HTTP 500).

Failure modes

SymptomLikely causeRecovery
PERMISSION_DENIED on writesWrong org, missing manage_portals, or SA not joined on interfaceSame org as list_portals; user runs portal admin join; try human admin token
Reads OK, writes fail on admin orgToken is human on org A, numeric id is org BAlign organization_uuid with token membership
Menu already created on create_portalMain deleted but org menu state remainsDelete orphan sub-portals; avoid raw createInterface; bootstrap with create_portal_page on existing UUID
Main page empty in builderPortal created outside create_portal template pathcreate_portal_page (title only) for templated elements
published missing on listExpectedget_portal
Many subs in get_portal, empty main UISub-portals not published to forms slotspublish_sub_portal per sub + forms element_id
Publish no effectWrong element type or skipped internal_api wireget_portal → forms element → publish_sub_portal
subPortals[] empty but UI shows tileLinked under pages[].elementsInspect type: subPortal in elements[]
create_portal_element opaque / 500Interfaces instability on some orgsduplicate_portal_element from existing widget on same page
Portal viewer HTTP 500Orphan layout children or wrong layout shapeCopy/fix layout from get_portal; delete disposable smoke page
Nested success: falseAPI rejected mutationRead error.message; do not assume top-level success
Validation on elementWrong metadata keys or partial updateFull metadata blob; linkName / name per type

See also

  • docs/mcp/tools/portal.md — endpoints, wire naming, maintainer introspection
  • pipefy-introspection — verify Interfaces / internal_api mutations before changing tools

FAQ

What does the pipefy-portal-setup skill do?

Use this skill when the user wants to list, create, or configure Pipefy portals (main hub, pages, page elements, sub-portals, publish/unpublish). Uses Interfaces and internalapi. Not for pipes/cards.

How do I install pipefy-portal-setup?

Run npx skills add https://github.com/pipefy/ai-toolkit --skill pipefy-portal-setup in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/pipefy-portal-setup/ (personal) or .claude/skills/pipefy-portal-setup/ (project).

Which AI agents can use pipefy-portal-setup?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is pipefy-portal-setup safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains pipefy-portal-setup?

It is published by pipefy in pipefy/ai-toolkit. It has 684 recorded installs.

More from pipefy/ai-toolkit

View all →

pipefy-observability

pipefy/ai-toolkit

Use this skill when the user wants to check AI agent logs, automation execution logs, org-level usage stats, AI credit consumption, or export automation job history.

DevOps & Cloud688 installs

pipefy-automations

pipefy/ai-toolkit

Use this skill when the user wants to create, read, update, or delete traditional automations (if/then rules) or AI automations (prompt-driven). For AI agents (conversational), see pipefy-ai-agents.

AI & Agents687 installs

pipefy-pipes-and-cards

pipefy/ai-toolkit

Use this skill when the user wants to read, create, update, or delete pipes, phases, phase fields, labels, cards, comments, or field conditions. Use the seed-pipe-across-phases workflow when populating empty phases for demos or QA.

Testing & QA685 installs

pipefy-introspection

pipefy/ai-toolkit

Use this skill when you need to discover GraphQL type shapes, mutation signatures, enum values, or execute arbitrary GraphQL as a fallback. This is the first fallback tier (Tier 2) when dedicated operations fail or don't exist for an operation.

Backend & APIs684 installs

pipefy-api-fallback

pipefy/ai-toolkit

Use this skill when a toolkit operation fails AND the introspection skill could not resolve the problem. This is the last-resort fallback (Tier 3): call the Pipefy GraphQL API directly using curl or httpx, authenticating with the Service Account (OAuth2) or a Personal Access Token (PAT) available as env var. Follow the 3-tier resolution strategy before reaching this point.

Backend & APIs684 installs

pipefy-process-design

pipefy/ai-toolkit

Use this skill ONLY when the user explicitly asks for help designing or architecting a process ("help me design", "what's the best structure", "how do I organize this flow?"). For direct execution requests ("create a pipe for X", "build a reimbursement process", or any message with a detailed spec), skip this skill and execute directly using the domain skills (pipes-and-cards, automations, etc.).

Popular backend & apis skills

View category →

find-skills

vercel-labs/skills

Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.

OfficialBackend & APIs4.1M installs

entra-app-registration

microsoft/azure-skills

Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.

OfficialBackend & APIs566.7K installs

This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).

Backend & APIs514.8K installs

embedded-captions

heygen-com/hyperframes

Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.

Backend & APIs453.3K installs

entra-agent-id

microsoft/azure-skills

Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).

OfficialBackend & APIs336.6K installs

neon

neondatabase/agent-skills

Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.

Backend & APIs237.1K installs